version update, boxblur tweak
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / boxblur / boxblur.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 1997-2020 Adam Williams <broadcast at earthling dot net>
5  *
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.
10  *
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.
15  *
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
19  *
20  */
21
22 #include "guicast.h"
23 #include "boxblur.h"
24 #include "filexml.h"
25 #include "language.h"
26 #include "pluginvclient.h"
27 #include "theme.h"
28
29 #include <stdint.h>
30 #include <string.h>
31
32 class BoxBlurConfig;
33 class BoxBlurRadius;
34 class BoxBlurPower;
35 class BoxBlurWindow;
36 class BoxBlurEffect;
37
38
39 class BoxBlurConfig
40 {
41 public:
42         BoxBlurConfig();
43         void copy_from(BoxBlurConfig &that);
44         int equivalent(BoxBlurConfig &that);
45         void interpolate(BoxBlurConfig &prev, BoxBlurConfig &next,
46                 int64_t prev_frame, int64_t next_frame, int64_t current_frame);
47
48         int horz_radius, vert_radius, power;
49 };
50
51
52 class BoxBlurRadius : public BC_ISlider
53 {
54 public:
55         BoxBlurRadius(BoxBlurWindow *gui, int x, int y, int w, int *radius);
56         int handle_event();
57
58         BoxBlurWindow *gui;
59         int *radius;
60 };
61
62 class BoxBlurPower : public BC_ISlider
63 {
64 public:
65         BoxBlurPower(BoxBlurWindow *gui, int x, int y, int w, int *power);
66         int handle_event();
67
68         BoxBlurWindow *gui;
69         int *power;
70 };
71
72 class BoxBlurWindow : public PluginClientWindow
73 {
74 public:
75         BoxBlurWindow(BoxBlurEffect *plugin);
76         ~BoxBlurWindow();
77         void create_objects();
78
79         BoxBlurEffect *plugin;
80         BoxBlurRadius *blur_horz;
81         BoxBlurRadius *blur_vert;
82         BoxBlurPower *blur_power;
83 };
84
85
86
87 class BoxBlurEffect : public PluginVClient
88 {
89 public:
90         BoxBlurEffect(PluginServer *server);
91         ~BoxBlurEffect();
92
93         PLUGIN_CLASS_MEMBERS(BoxBlurConfig)
94         int process_realtime(VFrame *input, VFrame *output);
95         void update_gui();
96         int is_realtime();
97         void save_data(KeyFrame *keyframe);
98         void read_data(KeyFrame *keyframe);
99
100         BoxBlur *box_blur;
101 };
102
103
104 BoxBlurConfig::BoxBlurConfig()
105 {
106         horz_radius = 2;
107         vert_radius = 2;
108         power = 2;
109 }
110
111 void BoxBlurConfig::copy_from(BoxBlurConfig &that)
112 {
113         horz_radius = that.horz_radius;
114         vert_radius = that.vert_radius;
115         power = that.power;
116 }
117
118 int BoxBlurConfig::equivalent(BoxBlurConfig &that)
119 {
120         return horz_radius == that.horz_radius &&
121                 vert_radius == that.vert_radius &&
122                 power == that.power;
123 }
124
125 void BoxBlurConfig::interpolate(BoxBlurConfig &prev, BoxBlurConfig &next,
126         int64_t prev_frame, int64_t next_frame, int64_t current_frame)
127 {
128         double u = (double)(next_frame - current_frame) / (next_frame - prev_frame);
129         double v = 1. - u;
130         this->horz_radius = u*prev.horz_radius + v*next.horz_radius;
131         this->vert_radius = u*prev.vert_radius + v*next.vert_radius;
132         this->power = u*prev.power + v*next.power;
133 }
134
135
136 BoxBlurRadius::BoxBlurRadius(BoxBlurWindow *gui, int x, int y, int w, int *radius)
137  : BC_ISlider(x, y, 0, w, w, 0, 100, *radius)
138 {
139         this->gui = gui;
140         this->radius = radius;
141 }
142 int BoxBlurRadius::handle_event()
143 {
144         *radius = get_value();
145         gui->plugin->send_configure_change();
146         return 1;
147 }
148
149 BoxBlurPower::BoxBlurPower(BoxBlurWindow *gui, int x, int y, int w, int *power)
150  : BC_ISlider(x, y, 0, w, w, 1, 10, *power)
151 {
152         this->gui = gui;
153         this->power = power;
154 }
155 int BoxBlurPower::handle_event()
156 {
157         *power = get_value();
158         gui->plugin->send_configure_change();
159         return 1;
160 }
161
162 BoxBlurWindow::BoxBlurWindow(BoxBlurEffect *plugin)
163  : PluginClientWindow(plugin, xS(200), yS(120), xS(200), yS(120), 0)
164 {
165         this->plugin = plugin;
166 }
167
168 BoxBlurWindow::~BoxBlurWindow()
169 {
170 }
171
172 void BoxBlurWindow::create_objects()
173 {
174         int x = xS(10), y = yS(10);
175         int x1 = xS(70), margin = plugin->get_theme()->widget_border;
176         BC_Title *title;
177         add_subwindow(title = new BC_Title(x, y, _("Box Blur"), MEDIUMFONT, YELLOW));
178         y += title->get_h() + 2*margin;
179         add_subwindow(title = new BC_Title(x, y, _("Horz:")));
180         add_subwindow(blur_horz = new BoxBlurRadius(this, x1, y, xS(120),
181                 &plugin->config.horz_radius));
182         y += blur_horz->get_h() + margin;
183         add_subwindow(title = new BC_Title(x, y, _("Vert:")));
184         add_subwindow(blur_vert = new BoxBlurRadius(this, x1, y, xS(120),
185                 &plugin->config.vert_radius));
186         y += blur_vert->get_h() + margin;
187         add_subwindow(title = new BC_Title(x, y, _("Power:")));
188         add_subwindow(blur_power = new BoxBlurPower(this, x1, y, xS(120),
189                 &plugin->config.power));
190         show_window(1);
191 }
192
193
194 REGISTER_PLUGIN(BoxBlurEffect)
195 NEW_WINDOW_MACRO(BoxBlurEffect, BoxBlurWindow)
196 LOAD_CONFIGURATION_MACRO(BoxBlurEffect, BoxBlurConfig)
197
198
199 BoxBlurEffect::BoxBlurEffect(PluginServer *server)
200  : PluginVClient(server)
201 {
202         box_blur = 0;
203 }
204
205 BoxBlurEffect::~BoxBlurEffect()
206 {
207         delete box_blur;
208 }
209
210 const char* BoxBlurEffect::plugin_title() { return N_("BoxBlur"); }
211 int BoxBlurEffect::is_realtime() { return 1; }
212
213
214 void BoxBlurEffect::save_data(KeyFrame *keyframe)
215 {
216         FileXML output;
217         output.set_shared_output(keyframe->xbuf);
218         output.tag.set_title("BOXBLUR");
219         output.tag.set_property("HORZ_RADIUS", config.horz_radius);
220         output.tag.set_property("VERT_RADIUS", config.vert_radius);
221         output.tag.set_property("POWER", config.power);
222         output.append_tag();
223         output.tag.set_title("/BOXBLUR");
224         output.append_tag();
225         output.append_newline();
226         output.terminate_string();
227 }
228
229 void BoxBlurEffect::read_data(KeyFrame *keyframe)
230 {
231         FileXML input;
232         input.set_shared_input(keyframe->xbuf);
233         int result = 0;
234
235         while( !(result = input.read_tag()) ) {
236                 if( input.tag.title_is("BOXBLUR") ) {
237                         config.horz_radius = input.tag.get_property("HORZ_RADIUS", config.horz_radius);
238                         config.vert_radius = input.tag.get_property("VERT_RADIUS", config.vert_radius);
239                         config.power = input.tag.get_property("POWER", config.power);
240                 }
241         }
242 }
243
244 int BoxBlurEffect::process_realtime(VFrame *input, VFrame *output)
245 {
246         load_configuration();
247         if( !box_blur ) {
248                 int cpus = input->get_w()*input->get_h()/0x80000 + 1;
249                 box_blur = new BoxBlur(cpus);
250         }
251         if( config.horz_radius ) {
252                 box_blur->hblur(output, input, config.horz_radius, config.power);
253                 input = output;
254         }
255         if( config.vert_radius )
256                 box_blur->vblur(output, input, config.vert_radius, config.power);
257         return 1;
258 }
259
260 void BoxBlurEffect::update_gui()
261 {
262         if( !thread ) return;
263         load_configuration();
264         thread->window->lock_window("BoxBlurEffect::update_gui");
265         BoxBlurWindow *gui = (BoxBlurWindow *)thread->window;
266         gui->blur_horz->update(config.horz_radius);
267         gui->blur_vert->update(config.vert_radius);
268         gui->blur_power->update(config.power);
269         thread->window->unlock_window();
270 }
271