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"
56 void copy_from(BoxBlurConfig &that);
57 int equivalent(BoxBlurConfig &that);
58 void interpolate(BoxBlurConfig &prev, BoxBlurConfig &next,
59 int64_t prev_frame, int64_t next_frame, int64_t current_frame);
62 int horz_radius, vert_radius, power;
69 class BoxBlurRadius : public BC_ISlider
72 BoxBlurRadius(BoxBlurWindow *gui, int x, int y, int w, int *radius);
79 class BoxBlurPower : public BC_ISlider
82 BoxBlurPower(BoxBlurWindow *gui, int x, int y, int w, int *power);
89 class BoxBlurX : public BC_TumbleTextBox
92 BoxBlurX(BoxBlurWindow *gui, int x, int y);
96 class BoxBlurY : public BC_TumbleTextBox
99 BoxBlurY(BoxBlurWindow *gui, int x, int y);
103 class BoxBlurW : public BC_TumbleTextBox
106 BoxBlurW(BoxBlurWindow *gui, int x, int y);
110 class BoxBlurH : public BC_TumbleTextBox
113 BoxBlurH(BoxBlurWindow *gui, int x, int y);
118 class BoxBlurDrag : public DragCheckBox
121 BoxBlurDrag(BoxBlurWindow *gui, BoxBlurEffect *plugin, int x, int y);
124 Track *get_drag_track();
125 int64_t get_drag_position();
128 BoxBlurEffect *plugin;
131 class BoxBlurReset : public BC_Button
134 BoxBlurReset(BoxBlurWindow *gui, int x, int y);
136 static int calculate_w(BoxBlurWindow *gui);
141 class BoxBlurWindow : public PluginClientWindow
144 BoxBlurWindow(BoxBlurEffect *plugin);
146 void create_objects();
150 BoxBlurEffect *plugin;
152 BoxBlurRadius *blur_horz;
153 BoxBlurRadius *blur_vert;
154 BoxBlurPower *blur_power;
163 class BoxBlurEffect : public PluginVClient
166 BoxBlurEffect(PluginServer *server);
169 PLUGIN_CLASS_MEMBERS(BoxBlurConfig)
170 int process_realtime(VFrame *input, VFrame *output);
173 void save_data(KeyFrame *keyframe);
174 void read_data(KeyFrame *keyframe);
177 VFrame *input, *output;
182 void BoxBlurConfig::reset()
192 BoxBlurConfig::BoxBlurConfig()
197 void BoxBlurConfig::copy_from(BoxBlurConfig &that)
199 horz_radius = that.horz_radius;
200 vert_radius = that.vert_radius;
203 box_x = that.box_x; box_y = that.box_y;
204 box_w = that.box_w; box_h = that.box_h;
207 int BoxBlurConfig::equivalent(BoxBlurConfig &that)
209 return horz_radius == that.horz_radius &&
210 vert_radius == that.vert_radius &&
211 power == that.power && // drag == that.drag &&
212 EQUIV(box_x, that.box_x) && EQUIV(box_y, that.box_y) &&
213 box_w == that.box_w && box_h == that.box_h;
216 void BoxBlurConfig::interpolate(BoxBlurConfig &prev, BoxBlurConfig &next,
217 int64_t prev_frame, int64_t next_frame, int64_t current_frame)
219 double u = (double)(next_frame - current_frame) / (next_frame - prev_frame);
221 this->horz_radius = u*prev.horz_radius + v*next.horz_radius;
222 this->vert_radius = u*prev.vert_radius + v*next.vert_radius;
223 this->power = u*prev.power + v*next.power;
224 this->drag = prev.drag;
225 this->box_x = u*prev.box_x + v*next.box_x;
226 this->box_y = u*prev.box_y + v*next.box_y;
227 this->box_w = u*prev.box_w + v*next.box_w;
228 this->box_h = u*prev.box_h + v*next.box_h;
232 BoxBlurRadius::BoxBlurRadius(BoxBlurWindow *gui, int x, int y, int w, int *radius)
233 : BC_ISlider(x, y, 0, w, w, 0, 100, *radius)
236 this->radius = radius;
238 int BoxBlurRadius::handle_event()
240 *radius = get_value();
241 gui->plugin->send_configure_change();
245 BoxBlurPower::BoxBlurPower(BoxBlurWindow *gui, int x, int y, int w, int *power)
246 : BC_ISlider(x, y, 0, w, w, 1, 10, *power)
251 int BoxBlurPower::handle_event()
253 *power = get_value();
254 gui->plugin->send_configure_change();
258 BoxBlurWindow::BoxBlurWindow(BoxBlurEffect *plugin)
259 : PluginClientWindow(plugin, xS(250), yS(185), xS(250), yS(185), 0)
261 this->plugin = plugin;
262 box_x = 0; box_y = 0;
263 box_w = 0; box_h = 0;
266 BoxBlurWindow::~BoxBlurWindow()
274 void BoxBlurWindow::create_objects()
276 int x = xS(10), y = yS(10);
277 int t1 = x, t2 = t1+xS(24), t3 = get_w()/2, t4 = t3 + xS(24);
278 int margin = plugin->get_theme()->widget_border;
280 add_subwindow(title = new BC_Title(x, y, _("Box Blur"), MEDIUMFONT_3D));
281 add_subwindow(drag = new BoxBlurDrag(this, plugin, t3, y));
282 drag->create_objects();
283 if( plugin->config.drag && drag->drag_activate() )
284 eprintf("drag enabled, but compositor already grabbed\n");
285 int x1 = get_w() - BoxBlurReset::calculate_w(this) - 2*margin;
286 add_subwindow(reset = new BoxBlurReset(this, x1, y));
287 y += bmax(title->get_h(), drag->get_h()) + 2*margin;
289 add_subwindow(title = new BC_Title(t1, y, _("X:")));
290 box_x = new BoxBlurX(this, t2, y);
291 box_x->create_objects();
292 add_subwindow(title = new BC_Title(t3, y, _("W:")));
293 box_w = new BoxBlurW(this, t4, y);
294 box_w->create_objects();
295 y += bmax(title->get_h(), box_w->get_h()) + margin;
296 add_subwindow(title = new BC_Title(t1, y, _("Y:")));
297 box_y = new BoxBlurY(this, t2, y);
298 box_y->create_objects();
299 add_subwindow(title = new BC_Title(t3, y, _("H:")));
300 box_h = new BoxBlurH(this, t4, y);
301 box_h->create_objects();
302 y += bmax(title->get_h(), box_h->get_h()) + margin;
306 add_subwindow(title = new BC_Title(x, y, _("Horz:")));
307 add_subwindow(blur_horz = new BoxBlurRadius(this, x1, y, xS(160),
308 &plugin->config.horz_radius));
309 y += blur_horz->get_h() + margin;
310 add_subwindow(title = new BC_Title(x, y, _("Vert:")));
311 add_subwindow(blur_vert = new BoxBlurRadius(this, x1, y, xS(160),
312 &plugin->config.vert_radius));
313 y += blur_vert->get_h() + margin;
314 add_subwindow(title = new BC_Title(x, y, _("Power:")));
315 add_subwindow(blur_power = new BoxBlurPower(this, x1, y, xS(160),
316 &plugin->config.power));
317 y += blur_power->get_h() + margin;
322 void BoxBlurWindow::update_gui()
324 BoxBlurConfig &config = plugin->config;
325 blur_horz->update(config.horz_radius);
326 blur_vert->update(config.vert_radius);
327 blur_power->update(config.power);
328 box_x->update(config.box_x);
329 box_y->update(config.box_y);
330 box_w->update((int64_t)config.box_w);
331 box_h->update((int64_t)config.box_h);
332 drag->drag_x = config.box_x;
333 drag->drag_y = config.box_y;
334 drag->drag_w = config.box_w;
335 drag->drag_h = config.box_h;
339 REGISTER_PLUGIN(BoxBlurEffect)
340 NEW_WINDOW_MACRO(BoxBlurEffect, BoxBlurWindow)
341 LOAD_CONFIGURATION_MACRO(BoxBlurEffect, BoxBlurConfig)
344 BoxBlurEffect::BoxBlurEffect(PluginServer *server)
345 : PluginVClient(server)
350 BoxBlurEffect::~BoxBlurEffect()
355 const char* BoxBlurEffect::plugin_title() { return N_("BoxBlur"); }
356 int BoxBlurEffect::is_realtime() { return 1; }
359 void BoxBlurEffect::save_data(KeyFrame *keyframe)
362 output.set_shared_output(keyframe->xbuf);
363 output.tag.set_title("BOXBLUR");
364 output.tag.set_property("HORZ_RADIUS", config.horz_radius);
365 output.tag.set_property("VERT_RADIUS", config.vert_radius);
366 output.tag.set_property("POWER", config.power);
367 output.tag.set_property("DRAG", config.drag);
368 output.tag.set_property("BOX_X", config.box_x);
369 output.tag.set_property("BOX_Y", config.box_y);
370 output.tag.set_property("BOX_W", config.box_w);
371 output.tag.set_property("BOX_H", config.box_h);
373 output.tag.set_title("/BOXBLUR");
375 output.append_newline();
376 output.terminate_string();
379 void BoxBlurEffect::read_data(KeyFrame *keyframe)
382 input.set_shared_input(keyframe->xbuf);
385 while( !(result = input.read_tag()) ) {
386 if( input.tag.title_is("BOXBLUR") ) {
387 config.horz_radius = input.tag.get_property("HORZ_RADIUS", config.horz_radius);
388 config.vert_radius = input.tag.get_property("VERT_RADIUS", config.vert_radius);
389 config.power = input.tag.get_property("POWER", config.power);
390 config.drag = input.tag.get_property("DRAG", config.drag);
391 config.box_x = input.tag.get_property("BOX_X", config.box_x);
392 config.box_y = input.tag.get_property("BOX_Y", config.box_y);
393 config.box_w = input.tag.get_property("BOX_W", config.box_w);
394 config.box_h = input.tag.get_property("BOX_H", config.box_h);
399 void BoxBlurEffect::draw_boundry()
401 if( !gui_open() ) return;
402 int box_x = config.box_x, box_y = config.box_y;
403 int box_w = config.box_w ? config.box_w : input->get_w();
404 int box_h = config.box_h ? config.box_h : input->get_h();
405 DragCheckBox::draw_boundary(output, box_x, box_y, box_w, box_h);
408 int BoxBlurEffect::process_realtime(VFrame *input, VFrame *output)
411 this->output = output;
412 load_configuration();
413 int out_w = output->get_w(), out_h = output->get_h();
416 int cpus = (out_w * out_h)/0x80000 + 1;
417 box_blur = new BoxBlur(cpus);
419 int x = config.box_x, y = config.box_y;
420 int ow = config.box_w ? config.box_w : out_w;
421 int oh = config.box_h ? config.box_h : out_h;
422 if( config.horz_radius ) {
423 box_blur->hblur(output, input, config.horz_radius, config.power,
427 if( config.vert_radius ) {
428 box_blur->vblur(output, input, config.vert_radius, config.power,
438 void BoxBlurEffect::update_gui()
440 if( !thread ) return;
441 load_configuration();
442 thread->window->lock_window("BoxBlurEffect::update_gui");
443 BoxBlurWindow *gui = (BoxBlurWindow *)thread->window;
445 thread->window->unlock_window();
449 BoxBlurX::BoxBlurX(BoxBlurWindow *gui, int x, int y)
450 : BC_TumbleTextBox(gui, gui->plugin->config.box_x,
451 -32767.f, 32767.f, x, y, xS(64))
456 int BoxBlurX::handle_event()
458 gui->plugin->config.box_x = atof(get_text());
463 BoxBlurY::BoxBlurY(BoxBlurWindow *gui, int x, int y)
464 : BC_TumbleTextBox(gui, gui->plugin->config.box_y,
465 -32767.f, 32767.f, x, y, xS(64))
470 int BoxBlurY::handle_event()
472 gui->plugin->config.box_y = atof(get_text());
477 BoxBlurW::BoxBlurW(BoxBlurWindow *gui, int x, int y)
478 : BC_TumbleTextBox(gui, gui->plugin->config.box_w,
479 0, 32767, x, y, xS(64))
483 int BoxBlurW::handle_event()
485 gui->plugin->config.box_w = atol(get_text());
490 BoxBlurH::BoxBlurH(BoxBlurWindow *gui, int x, int y)
491 : BC_TumbleTextBox(gui, gui->plugin->config.box_h,
492 0, 32767, x, y, xS(64))
496 int BoxBlurH::handle_event()
498 gui->plugin->config.box_h = atol(get_text());
503 BoxBlurDrag::BoxBlurDrag(BoxBlurWindow *gui, BoxBlurEffect *plugin, int x, int y)
504 : DragCheckBox(plugin->server->mwindow, x, y, _("Drag"), &plugin->config.drag,
505 plugin->config.box_x, plugin->config.box_y,
506 plugin->config.box_w, plugin->config.box_h)
508 this->plugin = plugin;
512 Track *BoxBlurDrag::get_drag_track()
514 PluginServer *server = plugin->server;
515 int plugin_id = server->plugin_id;
516 Plugin *plugin = server->edl->tracks->plugin_exists(plugin_id);
517 return !plugin ? 0 : plugin->track;
519 int64_t BoxBlurDrag::get_drag_position()
521 return plugin->get_source_position();
524 void BoxBlurDrag::update_gui()
526 plugin->config.drag = get_value();
527 plugin->config.box_x = drag_x;
528 plugin->config.box_y = drag_y;
529 plugin->config.box_w = drag_w+0.5;
530 plugin->config.box_h = drag_h+0.5;
531 gui->box_x->update((float)plugin->config.box_x);
532 gui->box_y->update((float)plugin->config.box_y);
533 gui->box_w->update((int64_t)plugin->config.box_w);
534 gui->box_h->update((int64_t)plugin->config.box_h);
535 plugin->send_configure_change();
538 int BoxBlurDrag::handle_event()
540 int ret = DragCheckBox::handle_event();
541 plugin->send_configure_change();
545 void BoxBlurWindow::update_drag()
547 drag->drag_x = plugin->config.box_x;
548 drag->drag_y = plugin->config.box_y;
549 drag->drag_w = plugin->config.box_w;
550 drag->drag_h = plugin->config.box_h;
551 plugin->send_configure_change();
554 BoxBlurReset::BoxBlurReset(BoxBlurWindow *gui, int x, int y)
555 : BC_Button(x, y, gui->plugin->get_theme()->get_image_set("reset_button"))
560 int BoxBlurReset::calculate_w(BoxBlurWindow *gui)
562 VFrame **imgs = gui->plugin->get_theme()->get_image_set("reset_button");
563 return imgs[0]->get_w();
566 int BoxBlurReset::handle_event()
568 BoxBlurEffect *plugin = gui->plugin;
569 plugin->config.reset();