preview tooltip, ffv1 fmt, opengl overlay tweaks, clear nested render output bfr
[goodguy/history.git] / cinelerra-5.1 / plugins / rumbler / rumbler.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 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 "bcdisplayinfo.h"
23 #include "affine.h"
24 #include "clip.h"
25 #include "bchash.h"
26 #include "filexml.h"
27 #include "guicast.h"
28 #include "keyframe.h"
29 #include "language.h"
30 #include "pluginvclient.h"
31 #include "vframe.h"
32
33 #include <math.h>
34 #include <string.h>
35 #include <stdint.h>
36
37
38 class Rumbler;
39 class RumblerConfig;
40 class RumblerRate;
41 class RumblerSeq;
42 class RumblerWindow;
43
44
45 class RumblerConfig
46 {
47 public:
48         RumblerConfig();
49         float time_rumble, time_rate;
50         float space_rumble, space_rate;
51         int sequence;
52         void copy_from(RumblerConfig &that);
53         int equivalent(RumblerConfig &that);
54         void interpolate(RumblerConfig &prev, RumblerConfig &next,
55                 int64_t prev_frame, int64_t next_frame, int64_t current_frame);
56 };
57
58 class RumblerRate : public BC_TextBox
59 {
60 public:
61         RumblerRate(Rumbler *plugin, RumblerWindow *gui,
62                 float &value, int x, int y);
63         int handle_event();
64         Rumbler *plugin;
65         RumblerWindow *gui;
66         float *value;
67 };
68
69 class RumblerSeq : public BC_TextBox
70 {
71 public:
72         RumblerSeq(Rumbler *plugin, RumblerWindow *gui,
73                 int &value, int x, int y);
74         int handle_event();
75         Rumbler *plugin;
76         RumblerWindow *gui;
77         int *value;
78 };
79
80
81 class RumblerWindow : public PluginClientWindow
82 {
83 public:
84         RumblerWindow(Rumbler *plugin);
85         ~RumblerWindow();
86         void create_objects();
87
88         Rumbler *plugin;
89         RumblerRate *time_rumble, *time_rate;
90         RumblerRate *space_rumble, *space_rate;
91         RumblerSeq *seq;
92 };
93
94 class Rumbler : public PluginVClient
95 {
96 public:
97         Rumbler(PluginServer *server);
98         ~Rumbler();
99
100         PLUGIN_CLASS_MEMBERS(RumblerConfig)
101
102         int process_buffer(VFrame *frame, int64_t start_position, double frame_rate);
103         int is_realtime();
104         void save_data(KeyFrame *keyframe);
105         void read_data(KeyFrame *keyframe);
106         void update_gui();
107         int handle_opengl();
108         static double rumble(int64_t seq, double cur, double per, double amp);
109
110         VFrame *input, *output, *temp;
111         float x1,y1, x2,y2, x3,y3, x4,y4;
112         AffineEngine *engine;
113 };
114
115
116 RumblerConfig::RumblerConfig()
117 {
118         time_rumble = 10;
119         time_rate = 1.;
120         space_rumble = 10;
121         space_rate = 1.;
122         sequence = 0;
123 }
124
125 void RumblerConfig::copy_from(RumblerConfig &that)
126 {
127         time_rumble = that.time_rumble;
128         time_rate = that.time_rate;
129         space_rumble = that.space_rumble;
130         space_rate = that.space_rate;
131         sequence = that.sequence;
132 }
133
134 int RumblerConfig::equivalent(RumblerConfig &that)
135 {
136         return time_rumble == that.time_rumble &&
137                 time_rate == that.time_rate &&
138                 space_rumble == that.space_rumble &&
139                 space_rate == that.space_rate &&
140                 sequence == that.sequence;
141 }
142
143 void RumblerConfig::interpolate(RumblerConfig &prev, RumblerConfig &next,
144         int64_t prev_frame, int64_t next_frame, int64_t current_frame)
145 {
146         double next_scale  = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
147         double prev_scale  = (double)(next_frame - current_frame) / (next_frame - prev_frame);
148         this->time_rumble  = prev.time_rumble * prev_scale + next.time_rumble * next_scale;
149         this->time_rate    = prev.time_rate * prev_scale + next.time_rate * next_scale;
150         this->space_rumble = prev.space_rumble * prev_scale + next.space_rumble * next_scale;
151         this->space_rate   = prev.space_rate * prev_scale + next.space_rate * next_scale;
152         this->sequence     = prev.sequence;
153 }
154
155 RumblerWindow::RumblerWindow(Rumbler *plugin)
156  : PluginClientWindow(plugin, 300, 120, 300, 120, 0)
157 {
158         this->plugin = plugin;
159 }
160
161 RumblerWindow::~RumblerWindow()
162 {
163 }
164
165 void RumblerWindow::create_objects()
166 {
167         int x = 10, x1 = x + 64, x2 =x1 + 100;
168         int y = 10;
169         BC_Title *title;
170
171         add_subwindow(title = new BC_Title(x1, y, _("rumble")));
172         add_subwindow(title = new BC_Title(x2, y, _("rate")));
173         y += title->get_h() + 10;
174         add_subwindow(title = new BC_Title(x, y, _("time:")));
175         add_subwindow(time_rumble = new RumblerRate(plugin, this, plugin->config.time_rumble, x1, y));
176         add_subwindow(time_rate = new RumblerRate(plugin, this, plugin->config.time_rate, x2, y));
177         y += title->get_h() + 10;
178         add_subwindow(title = new BC_Title(x, y, _("space:")));
179         add_subwindow(space_rumble = new RumblerRate(plugin, this, plugin->config.space_rumble, x1, y));
180         add_subwindow(space_rate = new RumblerRate(plugin, this, plugin->config.space_rate, x2, y));
181         y += title->get_h() + 10;
182         add_subwindow(title = new BC_Title(x, y, _("seq:")));
183         add_subwindow(seq = new RumblerSeq(plugin, this, plugin->config.sequence, x1, y));
184
185         show_window();
186         flush();
187 }
188
189
190 RumblerRate::RumblerRate(Rumbler *plugin, RumblerWindow *gui,
191         float &value, int x, int y)
192  : BC_TextBox(x, y, 90, 1, value)
193 {
194         this->plugin = plugin;
195         this->value = &value;
196         this->gui = gui;
197 }
198
199 int RumblerRate::handle_event()
200 {
201         *value = atof(get_text());
202         plugin->send_configure_change();
203         return 1;
204 }
205
206 RumblerSeq::RumblerSeq(Rumbler *plugin, RumblerWindow *gui,
207         int &value, int x, int y)
208  : BC_TextBox(x, y, 72, 1, value)
209 {
210         this->plugin = plugin;
211         this->value = &value;
212         this->gui = gui;
213 }
214
215 int RumblerSeq::handle_event()
216 {
217         *value = atoi(get_text());
218         plugin->send_configure_change();
219         return 1;
220 }
221
222
223 REGISTER_PLUGIN(Rumbler)
224
225 Rumbler::Rumbler(PluginServer *server)
226  : PluginVClient(server)
227 {
228         engine = 0;
229 }
230
231 Rumbler::~Rumbler()
232 {
233         delete engine;
234 }
235
236
237 double Rumbler::rumble(int64_t seq, double cur, double per, double amp)
238 {
239         if( !per || !amp ) return 0.;
240         int64_t t = cur / per;
241         double t0 = t * per;
242         srandom(t += seq);
243         static const int64_t rmax1 = ((int64_t)RAND_MAX) + 1;
244         double prev = (double)random() / rmax1 - 0.5;
245         srandom(t+1);
246         double next = (double)random() / rmax1 - 0.5;
247         double v = (cur-t0) / per, u = 1. - v;
248         return amp*(u*prev + v*next);
249 }
250
251 int Rumbler::process_buffer(VFrame *frame, int64_t start_position, double frame_rate)
252 {
253         load_configuration();
254         input = frame;
255         output = frame;
256         double cur = frame_rate > 0 ? start_position / frame_rate : 0;
257         double per = config.time_rate > 0 ? 1./config.time_rate : 0;
258         double rum = config.time_rumble;
259         int seq = config.sequence;
260         int64_t pos = rumble(seq+0x0000000, cur, per, rum) + start_position;
261         read_frame(frame, 0, pos, frame_rate, 0);
262         cur = frame_rate > 0 ? start_position / frame_rate : 0;
263         per = config.space_rate > 0 ? 1./config.space_rate : 0;
264         rum = config.space_rumble;
265         x1 = rumble(seq+0x1000000, cur, per, rum) + 0;
266         y1 = rumble(seq+0x2000000, cur, per, rum) + 0;
267         x2 = rumble(seq+0x3000000, cur, per, rum) + 100;
268         y2 = rumble(seq+0x4000000, cur, per, rum) + 0;
269         x3 = rumble(seq+0x5000000, cur, per, rum) + 100;
270         y3 = rumble(seq+0x6000000, cur, per, rum) + 100;
271         x4 = rumble(seq+0x7000000, cur, per, rum) + 0;
272         y4 = rumble(seq+0x8000000, cur, per, rum) + 100;
273         if( !engine ) {
274                 int cpus = get_project_smp() + 1;
275                 engine = new AffineEngine(cpus, cpus);
276         }
277
278         if( get_use_opengl() )
279                 return run_opengl();
280
281         int w = frame->get_w(), h = frame->get_h();
282         int color_model = frame->get_color_model();
283         input = new_temp(w, h, color_model);
284         input->copy_from(frame);
285         output->clear_frame();
286         engine->process(output, input, input,
287                 AffineEngine::PERSPECTIVE,
288                 x1, y1, x2, y2, x3, y3, x4, y4, 1);
289
290         return 0;
291 }
292
293 int Rumbler::handle_opengl()
294 {
295 #ifdef HAVE_GL
296         engine->set_opengl(1);
297         engine->process(output, input, input,
298                 AffineEngine::PERSPECTIVE,
299                 x1, y1, x2, y2, x3, y3, x4, y4, 1);
300         engine->set_opengl(0);
301 #endif
302         return 0;
303 }
304
305
306 const char* Rumbler::plugin_title() { return N_("Rumbler"); }
307 int Rumbler::is_realtime() { return 1; }
308
309 NEW_WINDOW_MACRO(Rumbler, RumblerWindow)
310
311 LOAD_CONFIGURATION_MACRO(Rumbler, RumblerConfig)
312
313 void Rumbler::save_data(KeyFrame *keyframe)
314 {
315         FileXML output;
316
317         output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
318         output.tag.set_title("RUMBLER");
319         output.tag.set_property("TIME_RUMBLE", config.time_rumble);
320         output.tag.set_property("TIME_RATE", config.time_rate);
321         output.tag.set_property("SPACE_RUMBLE", config.space_rumble);
322         output.tag.set_property("SPACE_RATE", config.space_rate);
323         output.tag.set_property("SEQUENCE", config.sequence);
324         output.append_tag();
325         output.tag.set_title("/RUMBLER");
326         output.append_tag();
327         output.append_newline();
328         output.terminate_string();
329 }
330
331 void Rumbler::read_data(KeyFrame *keyframe)
332 {
333         FileXML input;
334
335         input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
336
337         while( !input.read_tag() ) {
338                 if( input.tag.title_is("RUMBLER") ) {
339                         config.time_rumble = input.tag.get_property("TIME_RUMBLE", config.time_rumble);
340                         config.time_rate = input.tag.get_property("TIME_RATE", config.time_rate);
341                         config.space_rumble = input.tag.get_property("SPACE_RUMBLE", config.space_rumble);
342                         config.space_rate = input.tag.get_property("SPACE_RATE", config.space_rate);
343                         config.sequence = input.tag.get_property("SEQUENCE", config.sequence);
344                 }
345         }
346 }
347
348 void Rumbler::update_gui()
349 {
350         if( !thread ) return;
351         if( !load_configuration() ) return;
352         RumblerWindow *window = (RumblerWindow*)thread->window;
353         window->lock_window("Rumbler::update_gui");
354         window->time_rumble->update(config.time_rumble);
355         window->time_rate->update(config.time_rate);
356         window->space_rumble->update(config.space_rumble);
357         window->space_rate->update(config.space_rate);
358         window->seq->update((float)config.sequence);
359         window->unlock_window();
360 }
361