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()
235 int ys10 = yS(10), ys30 = yS(30);
236 int x = xs10, y = ys10;
238 add_subwindow(new BC_Title(x, y, _("Horizontal")));
240 add_subwindow(h = new DownSampleSize(plugin,
243 &plugin->config.horizontal,
247 add_subwindow(new BC_Title(x, y, _("Horizontal offset")));
249 add_subwindow(h_x = new DownSampleSize(plugin,
252 &plugin->config.horizontal_x,
256 add_subwindow(new BC_Title(x, y, _("Vertical")));
258 add_subwindow(v = new DownSampleSize(plugin,
261 &plugin->config.vertical,
265 add_subwindow(new BC_Title(x, y, _("Vertical offset")));
267 add_subwindow(v_y = new DownSampleSize(plugin,
270 &plugin->config.vertical_y,
274 add_subwindow(r = new DownSampleToggle(plugin,
280 add_subwindow(g = new DownSampleToggle(plugin,
286 add_subwindow(b = new DownSampleToggle(plugin,
292 add_subwindow(a = new DownSampleToggle(plugin,
313 DownSampleToggle::DownSampleToggle(DownSampleMain *plugin,
318 : BC_CheckBox(x, y, *output, string)
320 this->plugin = plugin;
321 this->output = output;
324 int DownSampleToggle::handle_event()
326 *output = get_value();
327 plugin->send_configure_change();
337 DownSampleSize::DownSampleSize(DownSampleMain *plugin,
343 : BC_ISlider(x, y, 0, xS(200), yS(200), min, max, *output)
345 this->plugin = plugin;
346 this->output = output;
348 int DownSampleSize::handle_event()
350 *output = get_value();
351 plugin->send_configure_change();
364 DownSampleMain::DownSampleMain(PluginServer *server)
365 : PluginVClient(server)
371 DownSampleMain::~DownSampleMain()
375 if(engine) delete engine;
378 const char* DownSampleMain::plugin_title() { return N_("Downsample"); }
379 int DownSampleMain::is_realtime() { return 1; }
382 NEW_WINDOW_MACRO(DownSampleMain, DownSampleWindow)
384 LOAD_CONFIGURATION_MACRO(DownSampleMain, DownSampleConfig)
387 int DownSampleMain::process_buffer(VFrame *frame,
388 int64_t start_position,
392 this->output = frame;
393 load_configuration();
395 // This can't be done efficiently in a shader because every output pixel
396 // requires summing a large, arbitrary block of the input pixels.
397 // Scaling down a texture wouldn't average every pixel.
398 read_frame(frame, 0, start_position, frame_rate, 0);
399 // get_use_opengl());
402 // if(get_use_opengl())
408 // Process in destination
409 if(!engine) engine = new DownSampleServer(get_project_smp() + 1,
410 get_project_smp() + 1);
411 engine->process_frame(output, output,
412 config.r, config.g, config.b, config.a,
413 config.vertical, config.horizontal,
414 config.vertical_y, config.horizontal_x);
420 void DownSampleMain::update_gui()
424 load_configuration();
425 ((DownSampleWindow*)thread->window)->lock_window();
426 ((DownSampleWindow*)thread->window)->h->update(config.horizontal);
427 ((DownSampleWindow*)thread->window)->v->update(config.vertical);
428 ((DownSampleWindow*)thread->window)->h_x->update(config.horizontal_x);
429 ((DownSampleWindow*)thread->window)->v_y->update(config.vertical_y);
430 ((DownSampleWindow*)thread->window)->r->update(config.r);
431 ((DownSampleWindow*)thread->window)->g->update(config.g);
432 ((DownSampleWindow*)thread->window)->b->update(config.b);
433 ((DownSampleWindow*)thread->window)->a->update(config.a);
434 ((DownSampleWindow*)thread->window)->unlock_window();
441 void DownSampleMain::save_data(KeyFrame *keyframe)
445 // cause data to be stored directly in text
446 output.set_shared_output(keyframe->xbuf);
447 output.tag.set_title("DOWNSAMPLE");
449 output.tag.set_property("HORIZONTAL", config.horizontal);
450 output.tag.set_property("VERTICAL", config.vertical);
451 output.tag.set_property("HORIZONTAL_X", config.horizontal_x);
452 output.tag.set_property("VERTICAL_Y", config.vertical_y);
453 output.tag.set_property("R", config.r);
454 output.tag.set_property("G", config.g);
455 output.tag.set_property("B", config.b);
456 output.tag.set_property("A", config.a);
458 output.tag.set_title("/DOWNSAMPLE");
460 output.append_newline();
461 output.terminate_string();
464 void DownSampleMain::read_data(KeyFrame *keyframe)
467 input.set_shared_input(keyframe->xbuf);
471 result = input.read_tag();
473 if(input.tag.title_is("DOWNSAMPLE")) {
474 config.horizontal = input.tag.get_property("HORIZONTAL", config.horizontal);
475 config.vertical = input.tag.get_property("VERTICAL", config.vertical);
476 config.horizontal_x = input.tag.get_property("HORIZONTAL_X", config.horizontal_x);
477 config.vertical_y = input.tag.get_property("VERTICAL_Y", config.vertical_y);
478 config.r = input.tag.get_property("R", config.r);
479 config.g = input.tag.get_property("G", config.g);
480 config.b = input.tag.get_property("B", config.b);
481 config.a = input.tag.get_property("A", config.a);
488 int DownSampleMain::handle_opengl()
491 static const char *downsample_frag =
492 "uniform sampler2D tex;\n"
495 "uniform float x_offset;\n"
496 "uniform float y_offset;\n";
497 (void) downsample_frag; // whatever