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