4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
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.
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.
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
22 #include "bcdisplayinfo.h"
30 #include "pluginvclient.h"
49 float time_rumble, time_rate;
50 float space_rumble, space_rate;
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);
58 class RumblerRate : public BC_TextBox
61 RumblerRate(Rumbler *plugin, RumblerWindow *gui,
62 float &value, int x, int y);
69 class RumblerSeq : public BC_TextBox
72 RumblerSeq(Rumbler *plugin, RumblerWindow *gui,
73 int &value, int x, int y);
81 class RumblerWindow : public PluginClientWindow
84 RumblerWindow(Rumbler *plugin);
86 void create_objects();
89 RumblerRate *time_rumble, *time_rate;
90 RumblerRate *space_rumble, *space_rate;
94 class Rumbler : public PluginVClient
97 Rumbler(PluginServer *server);
100 PLUGIN_CLASS_MEMBERS(RumblerConfig)
102 int process_buffer(VFrame *frame, int64_t start_position, double frame_rate);
104 void save_data(KeyFrame *keyframe);
105 void read_data(KeyFrame *keyframe);
108 static double rumble(int64_t seq, double cur, double per, double amp);
110 VFrame *input, *output, *temp;
111 float x1,y1, x2,y2, x3,y3, x4,y4;
112 AffineEngine *engine;
116 RumblerConfig::RumblerConfig()
125 void RumblerConfig::copy_from(RumblerConfig &that)
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;
134 int RumblerConfig::equivalent(RumblerConfig &that)
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;
143 void RumblerConfig::interpolate(RumblerConfig &prev, RumblerConfig &next,
144 int64_t prev_frame, int64_t next_frame, int64_t current_frame)
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;
155 RumblerWindow::RumblerWindow(Rumbler *plugin)
156 : PluginClientWindow(plugin, 300, 120, 300, 120, 0)
158 this->plugin = plugin;
161 RumblerWindow::~RumblerWindow()
165 void RumblerWindow::create_objects()
167 int x = 10, x1 = x + 64, x2 =x1 + 100;
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));
190 RumblerRate::RumblerRate(Rumbler *plugin, RumblerWindow *gui,
191 float &value, int x, int y)
192 : BC_TextBox(x, y, 90, 1, value)
194 this->plugin = plugin;
195 this->value = &value;
199 int RumblerRate::handle_event()
201 *value = atof(get_text());
202 plugin->send_configure_change();
206 RumblerSeq::RumblerSeq(Rumbler *plugin, RumblerWindow *gui,
207 int &value, int x, int y)
208 : BC_TextBox(x, y, 72, 1, value)
210 this->plugin = plugin;
211 this->value = &value;
215 int RumblerSeq::handle_event()
217 *value = atoi(get_text());
218 plugin->send_configure_change();
223 REGISTER_PLUGIN(Rumbler)
225 Rumbler::Rumbler(PluginServer *server)
226 : PluginVClient(server)
237 double Rumbler::rumble(int64_t seq, double cur, double per, double amp)
239 if( !per || !amp ) return 0.;
240 int64_t t = cur / per;
243 static const int64_t rmax1 = ((int64_t)RAND_MAX) + 1;
244 double prev = (double)random() / rmax1 - 0.5;
246 double next = (double)random() / rmax1 - 0.5;
247 double v = (cur-t0) / per, u = 1. - v;
248 return amp*(u*prev + v*next);
251 int Rumbler::process_buffer(VFrame *frame, int64_t start_position, double frame_rate)
253 load_configuration();
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;
274 int cpus = get_project_smp() + 1;
275 engine = new AffineEngine(cpus, cpus);
278 if( get_use_opengl() )
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);
293 int Rumbler::handle_opengl()
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);
306 const char* Rumbler::plugin_title() { return N_("Rumbler"); }
307 int Rumbler::is_realtime() { return 1; }
309 NEW_WINDOW_MACRO(Rumbler, RumblerWindow)
311 LOAD_CONFIGURATION_MACRO(Rumbler, RumblerConfig)
313 void Rumbler::save_data(KeyFrame *keyframe)
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);
325 output.tag.set_title("/RUMBLER");
327 output.append_newline();
328 output.terminate_string();
331 void Rumbler::read_data(KeyFrame *keyframe)
335 input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
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);
348 void Rumbler::update_gui()
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();