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"
29 #include "pluginserver.h"
30 #include "pluginvclient.h"
55 void copy_from(BoxBlurConfig &that);
56 int equivalent(BoxBlurConfig &that);
57 void interpolate(BoxBlurConfig &prev, BoxBlurConfig &next,
58 int64_t prev_frame, int64_t next_frame, int64_t current_frame);
61 int horz_radius, vert_radius, power;
68 class BoxBlurRadius : public BC_ISlider
71 BoxBlurRadius(BoxBlurWindow *gui, int x, int y, int w, int *radius);
78 class BoxBlurPower : public BC_ISlider
81 BoxBlurPower(BoxBlurWindow *gui, int x, int y, int w, int *power);
88 class BoxBlurX : public BC_TumbleTextBox
91 BoxBlurX(BoxBlurWindow *gui, int x, int y);
95 class BoxBlurY : public BC_TumbleTextBox
98 BoxBlurY(BoxBlurWindow *gui, int x, int y);
102 class BoxBlurW : public BC_TumbleTextBox
105 BoxBlurW(BoxBlurWindow *gui, int x, int y);
109 class BoxBlurH : public BC_TumbleTextBox
112 BoxBlurH(BoxBlurWindow *gui, int x, int y);
117 class BoxBlurDrag : public DragCheckBox
120 BoxBlurDrag(BoxBlurWindow *gui, BoxBlurEffect *plugin, int x, int y);
123 Track *get_drag_track();
124 int64_t get_drag_position();
127 BoxBlurEffect *plugin;
130 class BoxBlurReset : public BC_Button
133 BoxBlurReset(BoxBlurWindow *gui, int x, int y);
135 static int calculate_w(BoxBlurWindow *gui);
140 class BoxBlurWindow : public PluginClientWindow
143 BoxBlurWindow(BoxBlurEffect *plugin);
145 void create_objects();
149 BoxBlurEffect *plugin;
151 BoxBlurRadius *blur_horz;
152 BoxBlurRadius *blur_vert;
153 BoxBlurPower *blur_power;
162 class BoxBlurEffect : public PluginVClient
165 BoxBlurEffect(PluginServer *server);
168 PLUGIN_CLASS_MEMBERS(BoxBlurConfig)
169 int process_realtime(VFrame *input, VFrame *output);
172 void save_data(KeyFrame *keyframe);
173 void read_data(KeyFrame *keyframe);
176 VFrame *input, *output;
181 void BoxBlurConfig::reset()
191 BoxBlurConfig::BoxBlurConfig()
196 void BoxBlurConfig::copy_from(BoxBlurConfig &that)
198 horz_radius = that.horz_radius;
199 vert_radius = that.vert_radius;
202 box_x = that.box_x; box_y = that.box_y;
203 box_w = that.box_w; box_h = that.box_h;
206 int BoxBlurConfig::equivalent(BoxBlurConfig &that)
208 return horz_radius == that.horz_radius &&
209 vert_radius == that.vert_radius &&
210 power == that.power && // drag == that.drag &&
211 EQUIV(box_x, that.box_x) && EQUIV(box_y, that.box_y) &&
212 box_w == that.box_w && box_h == that.box_h;
215 void BoxBlurConfig::interpolate(BoxBlurConfig &prev, BoxBlurConfig &next,
216 int64_t prev_frame, int64_t next_frame, int64_t current_frame)
218 double u = (double)(next_frame - current_frame) / (next_frame - prev_frame);
220 this->horz_radius = u*prev.horz_radius + v*next.horz_radius;
221 this->vert_radius = u*prev.vert_radius + v*next.vert_radius;
222 this->power = u*prev.power + v*next.power;
223 this->drag = prev.drag;
224 this->box_x = u*prev.box_x + v*next.box_x;
225 this->box_y = u*prev.box_y + v*next.box_y;
226 this->box_w = u*prev.box_w + v*next.box_w;
227 this->box_h = u*prev.box_h + v*next.box_h;
231 BoxBlurRadius::BoxBlurRadius(BoxBlurWindow *gui, int x, int y, int w, int *radius)
232 : BC_ISlider(x, y, 0, w, w, 0, 100, *radius)
235 this->radius = radius;
237 int BoxBlurRadius::handle_event()
239 *radius = get_value();
240 gui->plugin->send_configure_change();
244 BoxBlurPower::BoxBlurPower(BoxBlurWindow *gui, int x, int y, int w, int *power)
245 : BC_ISlider(x, y, 0, w, w, 1, 10, *power)
250 int BoxBlurPower::handle_event()
252 *power = get_value();
253 gui->plugin->send_configure_change();
257 BoxBlurWindow::BoxBlurWindow(BoxBlurEffect *plugin)
258 : PluginClientWindow(plugin, xS(250), yS(185), xS(250), yS(185), 0)
260 this->plugin = plugin;
261 box_x = 0; box_y = 0;
262 box_w = 0; box_h = 0;
265 BoxBlurWindow::~BoxBlurWindow()
273 void BoxBlurWindow::create_objects()
275 int x = xS(10), y = yS(10);
276 int t1 = x, t2 = t1+xS(24), t3 = get_w()/2, t4 = t3 + xS(24);
277 int margin = plugin->get_theme()->widget_border;
279 add_subwindow(title = new BC_Title(x, y, _("Box Blur"), MEDIUMFONT_3D));
280 add_subwindow(drag = new BoxBlurDrag(this, plugin, t3, y));
281 drag->create_objects();
282 if( plugin->config.drag && drag->drag_activate() )
283 eprintf("drag enabled, but compositor already grabbed\n");
284 int x1 = get_w() - BoxBlurReset::calculate_w(this) - 2*margin;
285 add_subwindow(reset = new BoxBlurReset(this, x1, y));
286 y += bmax(title->get_h(), drag->get_h()) + 2*margin;
288 add_subwindow(title = new BC_Title(t1, y, _("X:")));
289 box_x = new BoxBlurX(this, t2, y);
290 box_x->create_objects();
291 add_subwindow(title = new BC_Title(t3, y, _("W:")));
292 box_w = new BoxBlurW(this, t4, y);
293 box_w->create_objects();
294 y += bmax(title->get_h(), box_w->get_h()) + margin;
295 add_subwindow(title = new BC_Title(t1, y, _("Y:")));
296 box_y = new BoxBlurY(this, t2, y);
297 box_y->create_objects();
298 add_subwindow(title = new BC_Title(t3, y, _("H:")));
299 box_h = new BoxBlurH(this, t4, y);
300 box_h->create_objects();
301 y += bmax(title->get_h(), box_h->get_h()) + margin;
305 add_subwindow(title = new BC_Title(x, y, _("Horz:")));
306 add_subwindow(blur_horz = new BoxBlurRadius(this, x1, y, xS(160),
307 &plugin->config.horz_radius));
308 y += blur_horz->get_h() + margin;
309 add_subwindow(title = new BC_Title(x, y, _("Vert:")));
310 add_subwindow(blur_vert = new BoxBlurRadius(this, x1, y, xS(160),
311 &plugin->config.vert_radius));
312 y += blur_vert->get_h() + margin;
313 add_subwindow(title = new BC_Title(x, y, _("Power:")));
314 add_subwindow(blur_power = new BoxBlurPower(this, x1, y, xS(160),
315 &plugin->config.power));
316 y += blur_power->get_h() + margin;
321 void BoxBlurWindow::update_gui()
323 BoxBlurConfig &config = plugin->config;
324 blur_horz->update(config.horz_radius);
325 blur_vert->update(config.vert_radius);
326 blur_power->update(config.power);
327 box_x->update(config.box_x);
328 box_y->update(config.box_y);
329 box_w->update((int64_t)config.box_w);
330 box_h->update((int64_t)config.box_h);
331 drag->drag_x = config.box_x;
332 drag->drag_y = config.box_y;
333 drag->drag_w = config.box_w;
334 drag->drag_h = config.box_h;
338 REGISTER_PLUGIN(BoxBlurEffect)
339 NEW_WINDOW_MACRO(BoxBlurEffect, BoxBlurWindow)
340 LOAD_CONFIGURATION_MACRO(BoxBlurEffect, BoxBlurConfig)
343 BoxBlurEffect::BoxBlurEffect(PluginServer *server)
344 : PluginVClient(server)
349 BoxBlurEffect::~BoxBlurEffect()
354 const char* BoxBlurEffect::plugin_title() { return N_("BoxBlur"); }
355 int BoxBlurEffect::is_realtime() { return 1; }
358 void BoxBlurEffect::save_data(KeyFrame *keyframe)
361 output.set_shared_output(keyframe->xbuf);
362 output.tag.set_title("BOXBLUR");
363 output.tag.set_property("HORZ_RADIUS", config.horz_radius);
364 output.tag.set_property("VERT_RADIUS", config.vert_radius);
365 output.tag.set_property("POWER", config.power);
366 output.tag.set_property("DRAG", config.drag);
367 output.tag.set_property("BOX_X", config.box_x);
368 output.tag.set_property("BOX_Y", config.box_y);
369 output.tag.set_property("BOX_W", config.box_w);
370 output.tag.set_property("BOX_H", config.box_h);
372 output.tag.set_title("/BOXBLUR");
374 output.append_newline();
375 output.terminate_string();
378 void BoxBlurEffect::read_data(KeyFrame *keyframe)
381 input.set_shared_input(keyframe->xbuf);
384 while( !(result = input.read_tag()) ) {
385 if( input.tag.title_is("BOXBLUR") ) {
386 config.horz_radius = input.tag.get_property("HORZ_RADIUS", config.horz_radius);
387 config.vert_radius = input.tag.get_property("VERT_RADIUS", config.vert_radius);
388 config.power = input.tag.get_property("POWER", config.power);
389 config.drag = input.tag.get_property("DRAG", config.drag);
390 config.box_x = input.tag.get_property("BOX_X", config.box_x);
391 config.box_y = input.tag.get_property("BOX_Y", config.box_y);
392 config.box_w = input.tag.get_property("BOX_W", config.box_w);
393 config.box_h = input.tag.get_property("BOX_H", config.box_h);
398 void BoxBlurEffect::draw_boundry()
400 if( !gui_open() ) return;
401 int box_x = config.box_x, box_y = config.box_y;
402 int box_w = config.box_w ? config.box_w : input->get_w();
403 int box_h = config.box_h ? config.box_h : input->get_h();
404 DragCheckBox::draw_boundary(output, box_x, box_y, box_w, box_h);
407 int BoxBlurEffect::process_realtime(VFrame *input, VFrame *output)
410 this->output = output;
411 load_configuration();
412 int out_w = output->get_w(), out_h = output->get_h();
415 int cpus = (out_w * out_h)/0x80000 + 1;
416 box_blur = new BoxBlur(cpus);
418 int x = config.box_x, y = config.box_y;
419 int ow = config.box_w ? config.box_w : out_w;
420 int oh = config.box_h ? config.box_h : out_h;
421 if( config.horz_radius ) {
422 box_blur->hblur(output, input, config.horz_radius, config.power,
426 if( config.vert_radius ) {
427 box_blur->vblur(output, input, config.vert_radius, config.power,
437 void BoxBlurEffect::update_gui()
439 if( !thread ) return;
440 load_configuration();
441 thread->window->lock_window("BoxBlurEffect::update_gui");
442 BoxBlurWindow *gui = (BoxBlurWindow *)thread->window;
444 thread->window->unlock_window();
448 BoxBlurX::BoxBlurX(BoxBlurWindow *gui, int x, int y)
449 : BC_TumbleTextBox(gui, gui->plugin->config.box_x,
450 -32767.f, 32767.f, x, y, xS(64))
455 int BoxBlurX::handle_event()
457 gui->plugin->config.box_x = atof(get_text());
462 BoxBlurY::BoxBlurY(BoxBlurWindow *gui, int x, int y)
463 : BC_TumbleTextBox(gui, gui->plugin->config.box_y,
464 -32767.f, 32767.f, x, y, xS(64))
469 int BoxBlurY::handle_event()
471 gui->plugin->config.box_y = atof(get_text());
476 BoxBlurW::BoxBlurW(BoxBlurWindow *gui, int x, int y)
477 : BC_TumbleTextBox(gui, gui->plugin->config.box_w,
478 0, 32767, x, y, xS(64))
482 int BoxBlurW::handle_event()
484 gui->plugin->config.box_w = atol(get_text());
489 BoxBlurH::BoxBlurH(BoxBlurWindow *gui, int x, int y)
490 : BC_TumbleTextBox(gui, gui->plugin->config.box_h,
491 0, 32767, x, y, xS(64))
495 int BoxBlurH::handle_event()
497 gui->plugin->config.box_h = atol(get_text());
502 BoxBlurDrag::BoxBlurDrag(BoxBlurWindow *gui, BoxBlurEffect *plugin, int x, int y)
503 : DragCheckBox(plugin->server->mwindow, x, y, _("Drag"), &plugin->config.drag,
504 plugin->config.box_x, plugin->config.box_y,
505 plugin->config.box_w, plugin->config.box_h)
507 this->plugin = plugin;
511 Track *BoxBlurDrag::get_drag_track()
513 PluginServer *server = plugin->server;
514 int plugin_id = server->plugin_id;
515 Plugin *plugin = server->edl->tracks->plugin_exists(plugin_id);
516 return !plugin ? 0 : plugin->track;
518 int64_t BoxBlurDrag::get_drag_position()
520 return plugin->get_source_position();
523 void BoxBlurDrag::update_gui()
525 plugin->config.drag = get_value();
526 plugin->config.box_x = drag_x;
527 plugin->config.box_y = drag_y;
528 plugin->config.box_w = drag_w+0.5;
529 plugin->config.box_h = drag_h+0.5;
530 gui->box_x->update((float)plugin->config.box_x);
531 gui->box_y->update((float)plugin->config.box_y);
532 gui->box_w->update((int64_t)plugin->config.box_w);
533 gui->box_h->update((int64_t)plugin->config.box_h);
534 plugin->send_configure_change();
537 int BoxBlurDrag::handle_event()
539 int ret = DragCheckBox::handle_event();
540 plugin->send_configure_change();
544 void BoxBlurWindow::update_drag()
546 drag->drag_x = plugin->config.box_x;
547 drag->drag_y = plugin->config.box_y;
548 drag->drag_w = plugin->config.box_w;
549 drag->drag_h = plugin->config.box_h;
550 plugin->send_configure_change();
553 BoxBlurReset::BoxBlurReset(BoxBlurWindow *gui, int x, int y)
554 : BC_Button(x, y, gui->plugin->get_theme()->get_image_set("reset_button"))
559 int BoxBlurReset::calculate_w(BoxBlurWindow *gui)
561 VFrame **imgs = gui->plugin->get_theme()->get_image_set("reset_button");
562 return imgs[0]->get_w();
565 int BoxBlurReset::handle_event()
567 BoxBlurEffect *plugin = gui->plugin;
568 plugin->config.reset();