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