add new boxblur plugin, mods to videoscope, fix segv for menu btns kfrm-tweak/kfrm...
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / boxblur / boxblur.C
diff --git a/cinelerra-5.1/plugins/boxblur/boxblur.C b/cinelerra-5.1/plugins/boxblur/boxblur.C
new file mode 100644 (file)
index 0000000..b141fe6
--- /dev/null
@@ -0,0 +1,271 @@
+
+/*
+ * CINELERRA
+ * Copyright (C) 1997-2020 Adam Williams <broadcast at earthling dot net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "guicast.h"
+#include "boxblur.h"
+#include "filexml.h"
+#include "language.h"
+#include "pluginvclient.h"
+#include "theme.h"
+
+#include <stdint.h>
+#include <string.h>
+
+class BoxBlurConfig;
+class BoxBlurRadius;
+class BoxBlurPower;
+class BoxBlurWindow;
+class BoxBlurEffect;
+
+
+class BoxBlurConfig
+{
+public:
+       BoxBlurConfig();
+       void copy_from(BoxBlurConfig &that);
+       int equivalent(BoxBlurConfig &that);
+       void interpolate(BoxBlurConfig &prev, BoxBlurConfig &next,
+               long prev_frame, long next_frame, long current_frame);
+
+       int horz_radius, vert_radius, power;
+};
+
+
+class BoxBlurRadius : public BC_ISlider
+{
+public:
+       BoxBlurRadius(BoxBlurWindow *gui, int x, int y, int w, int *radius);
+       int handle_event();
+
+       BoxBlurWindow *gui;
+       int *radius;
+};
+
+class BoxBlurPower : public BC_ISlider
+{
+public:
+       BoxBlurPower(BoxBlurWindow *gui, int x, int y, int w, int *power);
+       int handle_event();
+
+       BoxBlurWindow *gui;
+       int *power;
+};
+
+class BoxBlurWindow : public PluginClientWindow
+{
+public:
+       BoxBlurWindow(BoxBlurEffect *plugin);
+       ~BoxBlurWindow();
+       void create_objects();
+
+       BoxBlurEffect *plugin;
+       BoxBlurRadius *blur_horz;
+       BoxBlurRadius *blur_vert;
+       BoxBlurPower *blur_power;
+};
+
+
+
+class BoxBlurEffect : public PluginVClient
+{
+public:
+       BoxBlurEffect(PluginServer *server);
+       ~BoxBlurEffect();
+
+       PLUGIN_CLASS_MEMBERS(BoxBlurConfig)
+       int process_realtime(VFrame *input, VFrame *output);
+       void update_gui();
+       int is_realtime();
+       void save_data(KeyFrame *keyframe);
+       void read_data(KeyFrame *keyframe);
+
+       BoxBlur *box_blur;
+};
+
+
+BoxBlurConfig::BoxBlurConfig()
+{
+       horz_radius = 2;
+       vert_radius = 2;
+       power = 2;
+}
+
+void BoxBlurConfig::copy_from(BoxBlurConfig &that)
+{
+       horz_radius = that.horz_radius;
+       vert_radius = that.vert_radius;
+       power = that.power;
+}
+
+int BoxBlurConfig::equivalent(BoxBlurConfig &that)
+{
+       return horz_radius == that.horz_radius &&
+               vert_radius == that.vert_radius &&
+               power == that.power;
+}
+
+void BoxBlurConfig::interpolate(BoxBlurConfig &prev, BoxBlurConfig &next,
+       int64_t prev_frame, int64_t next_frame, int64_t current_frame)
+{
+       double u = (double)(next_frame - current_frame) / (next_frame - prev_frame);
+       double v = 1. - u;
+       this->horz_radius = u*prev.horz_radius + v*next.horz_radius;
+       this->vert_radius = u*prev.vert_radius + v*next.vert_radius;
+       this->power = u*prev.power + v*next.power;
+}
+
+
+BoxBlurRadius::BoxBlurRadius(BoxBlurWindow *gui, int x, int y, int w, int *radius)
+ : BC_ISlider(x, y, 0, w, w, 0, 100, *radius)
+{
+       this->gui = gui;
+       this->radius = radius;
+}
+int BoxBlurRadius::handle_event()
+{
+       *radius = get_value();
+       gui->plugin->send_configure_change();
+       return 1;
+}
+
+BoxBlurPower::BoxBlurPower(BoxBlurWindow *gui, int x, int y, int w, int *power)
+ : BC_ISlider(x, y, 0, w, w, 1, 10, *power)
+{
+       this->gui = gui;
+       this->power = power;
+}
+int BoxBlurPower::handle_event()
+{
+       *power = get_value();
+       gui->plugin->send_configure_change();
+       return 1;
+}
+
+BoxBlurWindow::BoxBlurWindow(BoxBlurEffect *plugin)
+ : PluginClientWindow(plugin, xS(200), yS(120), xS(200), yS(120), 0)
+{
+       this->plugin = plugin;
+}
+
+BoxBlurWindow::~BoxBlurWindow()
+{
+}
+
+void BoxBlurWindow::create_objects()
+{
+       int x = xS(10), y = yS(10);
+       int x1 = xS(70), margin = plugin->get_theme()->widget_border;
+       BC_Title *title;
+       add_subwindow(title = new BC_Title(x, y, _("Box Blur"), MEDIUMFONT, YELLOW));
+       y += title->get_h() + 2*margin;
+       add_subwindow(title = new BC_Title(x, y, _("Horz:")));
+       add_subwindow(blur_horz = new BoxBlurRadius(this, x1, y, xS(120),
+               &plugin->config.horz_radius));
+       y += blur_horz->get_h() + margin;
+       add_subwindow(title = new BC_Title(x, y, _("Vert:")));
+       add_subwindow(blur_vert = new BoxBlurRadius(this, x1, y, xS(120),
+               &plugin->config.vert_radius));
+       y += blur_vert->get_h() + margin;
+       add_subwindow(title = new BC_Title(x, y, _("Power:")));
+       add_subwindow(blur_power = new BoxBlurPower(this, x1, y, xS(120),
+               &plugin->config.power));
+       show_window(1);
+}
+
+
+REGISTER_PLUGIN(BoxBlurEffect)
+NEW_WINDOW_MACRO(BoxBlurEffect, BoxBlurWindow)
+LOAD_CONFIGURATION_MACRO(BoxBlurEffect, BoxBlurConfig)
+
+
+BoxBlurEffect::BoxBlurEffect(PluginServer *server)
+ : PluginVClient(server)
+{
+       box_blur = 0;
+}
+
+BoxBlurEffect::~BoxBlurEffect()
+{
+       delete box_blur;
+}
+
+const char* BoxBlurEffect::plugin_title() { return N_("BoxBlur"); }
+int BoxBlurEffect::is_realtime() { return 1; }
+
+
+void BoxBlurEffect::save_data(KeyFrame *keyframe)
+{
+       FileXML output;
+       output.set_shared_output(keyframe->xbuf);
+       output.tag.set_title("BOXBLUR");
+       output.tag.set_property("HORZ_RADIUS", config.horz_radius);
+       output.tag.set_property("VERT_RADIUS", config.vert_radius);
+       output.tag.set_property("POWER", config.power);
+       output.append_tag();
+       output.tag.set_title("/BOXBLUR");
+       output.append_tag();
+       output.append_newline();
+       output.terminate_string();
+}
+
+void BoxBlurEffect::read_data(KeyFrame *keyframe)
+{
+       FileXML input;
+       input.set_shared_input(keyframe->xbuf);
+       int result = 0;
+
+       while( !(result = input.read_tag()) ) {
+               if( input.tag.title_is("BOXBLUR") ) {
+                       config.horz_radius = input.tag.get_property("HORZ_RADIUS", config.horz_radius);
+                       config.vert_radius = input.tag.get_property("VERT_RADIUS", config.vert_radius);
+                       config.power = input.tag.get_property("POWER", config.power);
+               }
+       }
+}
+
+int BoxBlurEffect::process_realtime(VFrame *input, VFrame *output)
+{
+       load_configuration();
+       if( !box_blur ) {
+               int cpus = input->get_w()*input->get_h()/0x80000 + 1;
+               box_blur = new BoxBlur(cpus);
+       }
+       if( config.horz_radius ) {
+               box_blur->hblur(output, input, config.horz_radius, config.power);
+               input = output;
+       }
+       if( config.vert_radius )
+               box_blur->vblur(output, input, config.vert_radius, config.power);
+       return 1;
+}
+
+void BoxBlurEffect::update_gui()
+{
+       if( !thread ) return;
+       load_configuration();
+       thread->window->lock_window("BoxBlurEffect::update_gui");
+       BoxBlurWindow *gui = (BoxBlurWindow *)thread->window;
+       gui->blur_horz->update(config.horz_radius);
+       gui->blur_vert->update(config.vert_radius);
+       gui->blur_power->update(config.power);
+       thread->window->unlock_window();
+}
+