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 int x1 = get_w() - BoxBlurReset::calculate_w(this) - 2*margin;
283 add_subwindow(reset = new BoxBlurReset(this, x1, y));
284 y += bmax(title->get_h(), drag->get_h()) + 2*margin;
286 add_subwindow(title = new BC_Title(t1, y, _("X:")));
287 box_x = new BoxBlurX(this, t2, y);
288 box_x->create_objects();
289 add_subwindow(title = new BC_Title(t3, y, _("W:")));
290 box_w = new BoxBlurW(this, t4, y);
291 box_w->create_objects();
292 y += bmax(title->get_h(), box_w->get_h()) + margin;
293 add_subwindow(title = new BC_Title(t1, y, _("Y:")));
294 box_y = new BoxBlurY(this, t2, y);
295 box_y->create_objects();
296 add_subwindow(title = new BC_Title(t3, y, _("H:")));
297 box_h = new BoxBlurH(this, t4, y);
298 box_h->create_objects();
299 y += bmax(title->get_h(), box_h->get_h()) + margin;
303 add_subwindow(title = new BC_Title(x, y, _("Horz:")));
304 add_subwindow(blur_horz = new BoxBlurRadius(this, x1, y, xS(160),
305 &plugin->config.horz_radius));
306 y += blur_horz->get_h() + margin;
307 add_subwindow(title = new BC_Title(x, y, _("Vert:")));
308 add_subwindow(blur_vert = new BoxBlurRadius(this, x1, y, xS(160),
309 &plugin->config.vert_radius));
310 y += blur_vert->get_h() + margin;
311 add_subwindow(title = new BC_Title(x, y, _("Power:")));
312 add_subwindow(blur_power = new BoxBlurPower(this, x1, y, xS(160),
313 &plugin->config.power));
314 y += blur_power->get_h() + margin;
319 void BoxBlurWindow::update_gui()
321 BoxBlurConfig &config = plugin->config;
322 blur_horz->update(config.horz_radius);
323 blur_vert->update(config.vert_radius);
324 blur_power->update(config.power);
325 box_x->update(config.box_x);
326 box_y->update(config.box_y);
327 box_w->update((int64_t)config.box_w);
328 box_h->update((int64_t)config.box_h);
329 drag->drag_x = config.box_x;
330 drag->drag_y = config.box_y;
331 drag->drag_w = config.box_w;
332 drag->drag_h = config.box_h;
336 REGISTER_PLUGIN(BoxBlurEffect)
337 NEW_WINDOW_MACRO(BoxBlurEffect, BoxBlurWindow)
338 LOAD_CONFIGURATION_MACRO(BoxBlurEffect, BoxBlurConfig)
341 BoxBlurEffect::BoxBlurEffect(PluginServer *server)
342 : PluginVClient(server)
347 BoxBlurEffect::~BoxBlurEffect()
352 const char* BoxBlurEffect::plugin_title() { return N_("BoxBlur"); }
353 int BoxBlurEffect::is_realtime() { return 1; }
356 void BoxBlurEffect::save_data(KeyFrame *keyframe)
359 output.set_shared_output(keyframe->xbuf);
360 output.tag.set_title("BOXBLUR");
361 output.tag.set_property("HORZ_RADIUS", config.horz_radius);
362 output.tag.set_property("VERT_RADIUS", config.vert_radius);
363 output.tag.set_property("POWER", config.power);
364 output.tag.set_property("DRAG", config.drag);
365 output.tag.set_property("BOX_X", config.box_x);
366 output.tag.set_property("BOX_Y", config.box_y);
367 output.tag.set_property("BOX_W", config.box_w);
368 output.tag.set_property("BOX_H", config.box_h);
370 output.tag.set_title("/BOXBLUR");
372 output.append_newline();
373 output.terminate_string();
376 void BoxBlurEffect::read_data(KeyFrame *keyframe)
379 input.set_shared_input(keyframe->xbuf);
382 while( !(result = input.read_tag()) ) {
383 if( input.tag.title_is("BOXBLUR") ) {
384 config.horz_radius = input.tag.get_property("HORZ_RADIUS", config.horz_radius);
385 config.vert_radius = input.tag.get_property("VERT_RADIUS", config.vert_radius);
386 config.power = input.tag.get_property("POWER", config.power);
387 config.drag = input.tag.get_property("DRAG", config.drag);
388 config.box_x = input.tag.get_property("BOX_X", config.box_x);
389 config.box_y = input.tag.get_property("BOX_Y", config.box_y);
390 config.box_w = input.tag.get_property("BOX_W", config.box_w);
391 config.box_h = input.tag.get_property("BOX_H", config.box_h);
396 void BoxBlurEffect::draw_boundry()
398 if( !gui_open() ) return;
399 int box_x = config.box_x, box_y = config.box_y;
400 int box_w = config.box_w ? config.box_w : input->get_w();
401 int box_h = config.box_h ? config.box_h : input->get_h();
402 DragCheckBox::draw_boundary(output, box_x, box_y, box_w, box_h);
405 int BoxBlurEffect::process_realtime(VFrame *input, VFrame *output)
408 this->output = output;
409 load_configuration();
410 int out_w = output->get_w(), out_h = output->get_h();
413 int cpus = (out_w * out_h)/0x80000 + 1;
414 box_blur = new BoxBlur(cpus);
416 int x = config.box_x, y = config.box_y;
417 int ow = config.box_w ? config.box_w : out_w;
418 int oh = config.box_h ? config.box_h : out_h;
419 if( config.horz_radius ) {
420 box_blur->hblur(output, input, config.horz_radius, config.power,
424 if( config.vert_radius ) {
425 box_blur->vblur(output, input, config.vert_radius, config.power,
435 void BoxBlurEffect::update_gui()
437 if( !thread ) return;
438 load_configuration();
439 thread->window->lock_window("BoxBlurEffect::update_gui");
440 BoxBlurWindow *gui = (BoxBlurWindow *)thread->window;
442 thread->window->unlock_window();
446 BoxBlurX::BoxBlurX(BoxBlurWindow *gui, int x, int y)
447 : BC_TumbleTextBox(gui, gui->plugin->config.box_x,
448 -32767.f, 32767.f, x, y, xS(64))
453 int BoxBlurX::handle_event()
455 gui->plugin->config.box_x = atof(get_text());
460 BoxBlurY::BoxBlurY(BoxBlurWindow *gui, int x, int y)
461 : BC_TumbleTextBox(gui, gui->plugin->config.box_y,
462 -32767.f, 32767.f, x, y, xS(64))
467 int BoxBlurY::handle_event()
469 gui->plugin->config.box_y = atof(get_text());
474 BoxBlurW::BoxBlurW(BoxBlurWindow *gui, int x, int y)
475 : BC_TumbleTextBox(gui, gui->plugin->config.box_w,
476 0, 32767, x, y, xS(64))
480 int BoxBlurW::handle_event()
482 gui->plugin->config.box_w = atol(get_text());
487 BoxBlurH::BoxBlurH(BoxBlurWindow *gui, int x, int y)
488 : BC_TumbleTextBox(gui, gui->plugin->config.box_h,
489 0, 32767, x, y, xS(64))
493 int BoxBlurH::handle_event()
495 gui->plugin->config.box_h = atol(get_text());
500 BoxBlurDrag::BoxBlurDrag(BoxBlurWindow *gui, BoxBlurEffect *plugin, int x, int y)
501 : DragCheckBox(plugin->server->mwindow, x, y, _("Drag"), &plugin->config.drag,
502 plugin->config.box_x, plugin->config.box_y,
503 plugin->config.box_w, plugin->config.box_h)
505 this->plugin = plugin;
509 Track *BoxBlurDrag::get_drag_track()
511 PluginServer *server = plugin->server;
512 int plugin_id = server->plugin_id;
513 Plugin *plugin = server->edl->tracks->plugin_exists(plugin_id);
514 return !plugin ? 0 : plugin->track;
516 int64_t BoxBlurDrag::get_drag_position()
518 return plugin->get_source_position();
521 void BoxBlurDrag::update_gui()
523 plugin->config.drag = get_value();
524 plugin->config.box_x = drag_x;
525 plugin->config.box_y = drag_y;
526 plugin->config.box_w = drag_w+0.5;
527 plugin->config.box_h = drag_h+0.5;
528 gui->box_x->update((float)plugin->config.box_x);
529 gui->box_y->update((float)plugin->config.box_y);
530 gui->box_w->update((int64_t)plugin->config.box_w);
531 gui->box_h->update((int64_t)plugin->config.box_h);
532 plugin->send_configure_change();
535 int BoxBlurDrag::handle_event()
537 int ret = DragCheckBox::handle_event();
538 plugin->send_configure_change();
542 void BoxBlurWindow::update_drag()
544 drag->drag_x = plugin->config.box_x;
545 drag->drag_y = plugin->config.box_y;
546 drag->drag_w = plugin->config.box_w;
547 drag->drag_h = plugin->config.box_h;
548 plugin->send_configure_change();
551 BoxBlurReset::BoxBlurReset(BoxBlurWindow *gui, int x, int y)
552 : BC_Button(x, y, gui->plugin->get_theme()->get_image_set("reset_button"))
557 int BoxBlurReset::calculate_w(BoxBlurWindow *gui)
559 VFrame **imgs = gui->plugin->get_theme()->get_image_set("reset_button");
560 return imgs[0]->get_w();
563 int BoxBlurReset::handle_event()
565 BoxBlurEffect *plugin = gui->plugin;
566 plugin->config.reset();