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
26 #include "bcdisplayinfo.h"
29 #include "downsampleengine.h"
33 #include "pluginvclient.h"
38 class DownSampleServer;
44 class DownSampleConfig
49 int equivalent(DownSampleConfig &that);
50 void copy_from(DownSampleConfig &that);
51 void interpolate(DownSampleConfig &prev,
52 DownSampleConfig &next,
55 int64_t current_frame);
68 class DownSampleToggle : public BC_CheckBox
71 DownSampleToggle(DownSampleMain *plugin,
77 DownSampleMain *plugin;
81 class DownSampleSize : public BC_ISlider
84 DownSampleSize(DownSampleMain *plugin,
91 DownSampleMain *plugin;
95 class DownSampleWindow : public PluginClientWindow
98 DownSampleWindow(DownSampleMain *plugin);
101 void create_objects();
103 DownSampleToggle *r, *g, *b, *a;
104 DownSampleSize *h, *v, *h_x, *v_y;
105 DownSampleMain *plugin;
112 class DownSampleMain : public PluginVClient
115 DownSampleMain(PluginServer *server);
118 int process_buffer(VFrame *frame,
119 int64_t start_position,
122 void save_data(KeyFrame *keyframe);
123 void read_data(KeyFrame *keyframe);
127 PLUGIN_CLASS_MEMBERS(DownSampleConfig)
129 VFrame *input, *output;
130 DownSampleServer *engine;
147 REGISTER_PLUGIN(DownSampleMain)
151 DownSampleConfig::DownSampleConfig()
163 int DownSampleConfig::equivalent(DownSampleConfig &that)
166 horizontal == that.horizontal &&
167 vertical == that.vertical &&
168 horizontal_x == that.horizontal_x &&
169 vertical_y == that.vertical_y &&
176 void DownSampleConfig::copy_from(DownSampleConfig &that)
178 horizontal = that.horizontal;
179 vertical = that.vertical;
180 horizontal_x = that.horizontal_x;
181 vertical_y = that.vertical_y;
188 void DownSampleConfig::interpolate(DownSampleConfig &prev,
189 DownSampleConfig &next,
192 int64_t current_frame)
194 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
195 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
196 this->horizontal = (int)(prev.horizontal * prev_scale + next.horizontal * next_scale);
197 this->vertical = (int)(prev.vertical * prev_scale + next.vertical * next_scale);
198 this->horizontal_x = (int)(prev.horizontal_x * prev_scale + next.horizontal_x * next_scale);
199 this->vertical_y = (int)(prev.vertical_y * prev_scale + next.vertical_y * next_scale);
217 DownSampleWindow::DownSampleWindow(DownSampleMain *plugin)
218 : PluginClientWindow(plugin,
225 this->plugin = plugin;
228 DownSampleWindow::~DownSampleWindow()
232 void DownSampleWindow::create_objects()
236 add_subwindow(new BC_Title(x, y, _("Horizontal")));
238 add_subwindow(h = new DownSampleSize(plugin,
241 &plugin->config.horizontal,
245 add_subwindow(new BC_Title(x, y, _("Horizontal offset")));
247 add_subwindow(h_x = new DownSampleSize(plugin,
250 &plugin->config.horizontal_x,
254 add_subwindow(new BC_Title(x, y, _("Vertical")));
256 add_subwindow(v = new DownSampleSize(plugin,
259 &plugin->config.vertical,
263 add_subwindow(new BC_Title(x, y, _("Vertical offset")));
265 add_subwindow(v_y = new DownSampleSize(plugin,
268 &plugin->config.vertical_y,
272 add_subwindow(r = new DownSampleToggle(plugin,
278 add_subwindow(g = new DownSampleToggle(plugin,
284 add_subwindow(b = new DownSampleToggle(plugin,
290 add_subwindow(a = new DownSampleToggle(plugin,
311 DownSampleToggle::DownSampleToggle(DownSampleMain *plugin,
316 : BC_CheckBox(x, y, *output, string)
318 this->plugin = plugin;
319 this->output = output;
322 int DownSampleToggle::handle_event()
324 *output = get_value();
325 plugin->send_configure_change();
335 DownSampleSize::DownSampleSize(DownSampleMain *plugin,
341 : BC_ISlider(x, y, 0, 200, 200, min, max, *output)
343 this->plugin = plugin;
344 this->output = output;
346 int DownSampleSize::handle_event()
348 *output = get_value();
349 plugin->send_configure_change();
362 DownSampleMain::DownSampleMain(PluginServer *server)
363 : PluginVClient(server)
369 DownSampleMain::~DownSampleMain()
373 if(engine) delete engine;
376 const char* DownSampleMain::plugin_title() { return _("Downsample"); }
377 int DownSampleMain::is_realtime() { return 1; }
380 NEW_WINDOW_MACRO(DownSampleMain, DownSampleWindow)
382 LOAD_CONFIGURATION_MACRO(DownSampleMain, DownSampleConfig)
385 int DownSampleMain::process_buffer(VFrame *frame,
386 int64_t start_position,
390 this->output = frame;
391 load_configuration();
393 // This can't be done efficiently in a shader because every output pixel
394 // requires summing a large, arbitrary block of the input pixels.
395 // Scaling down a texture wouldn't average every pixel.
396 read_frame(frame, 0, start_position, frame_rate, 0);
397 // get_use_opengl());
400 // if(get_use_opengl())
406 // Process in destination
407 if(!engine) engine = new DownSampleServer(get_project_smp() + 1,
408 get_project_smp() + 1);
409 engine->process_frame(output, output,
410 config.r, config.g, config.b, config.a,
411 config.vertical, config.horizontal,
412 config.vertical_y, config.horizontal_x);
418 void DownSampleMain::update_gui()
422 load_configuration();
423 ((DownSampleWindow*)thread->window)->lock_window();
424 ((DownSampleWindow*)thread->window)->h->update(config.horizontal);
425 ((DownSampleWindow*)thread->window)->v->update(config.vertical);
426 ((DownSampleWindow*)thread->window)->h_x->update(config.horizontal_x);
427 ((DownSampleWindow*)thread->window)->v_y->update(config.vertical_y);
428 ((DownSampleWindow*)thread->window)->r->update(config.r);
429 ((DownSampleWindow*)thread->window)->g->update(config.g);
430 ((DownSampleWindow*)thread->window)->b->update(config.b);
431 ((DownSampleWindow*)thread->window)->a->update(config.a);
432 ((DownSampleWindow*)thread->window)->unlock_window();
439 void DownSampleMain::save_data(KeyFrame *keyframe)
443 // cause data to be stored directly in text
444 output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
445 output.tag.set_title("DOWNSAMPLE");
447 output.tag.set_property("HORIZONTAL", config.horizontal);
448 output.tag.set_property("VERTICAL", config.vertical);
449 output.tag.set_property("HORIZONTAL_X", config.horizontal_x);
450 output.tag.set_property("VERTICAL_Y", config.vertical_y);
451 output.tag.set_property("R", config.r);
452 output.tag.set_property("G", config.g);
453 output.tag.set_property("B", config.b);
454 output.tag.set_property("A", config.a);
456 output.tag.set_title("/DOWNSAMPLE");
458 output.append_newline();
459 output.terminate_string();
462 void DownSampleMain::read_data(KeyFrame *keyframe)
465 input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
469 result = input.read_tag();
471 if(input.tag.title_is("DOWNSAMPLE")) {
472 config.horizontal = input.tag.get_property("HORIZONTAL", config.horizontal);
473 config.vertical = input.tag.get_property("VERTICAL", config.vertical);
474 config.horizontal_x = input.tag.get_property("HORIZONTAL_X", config.horizontal_x);
475 config.vertical_y = input.tag.get_property("VERTICAL_Y", config.vertical_y);
476 config.r = input.tag.get_property("R", config.r);
477 config.g = input.tag.get_property("G", config.g);
478 config.b = input.tag.get_property("B", config.b);
479 config.a = input.tag.get_property("A", config.a);
486 int DownSampleMain::handle_opengl()
489 static const char *downsample_frag =
490 "uniform sampler2D tex;\n"
493 "uniform float x_offset;\n"
494 "uniform float y_offset;\n";
495 (void) downsample_frag; // whatever