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 REGISTER_PLUGIN(RGBShiftEffect)
33 RGBShiftConfig::RGBShiftConfig()
38 void RGBShiftConfig::reset(int clear)
41 case RESET_R_DX : r_dx = 0;
43 case RESET_R_DY : r_dy = 0;
45 case RESET_G_DX : g_dx = 0;
47 case RESET_G_DY : g_dy = 0;
49 case RESET_B_DX : b_dx = 0;
51 case RESET_B_DY : b_dy = 0;
62 void RGBShiftConfig::copy_from(RGBShiftConfig &src)
64 r_dx = src.r_dx; r_dy = src.r_dy;
65 g_dx = src.g_dx; g_dy = src.g_dy;
66 b_dx = src.b_dx; b_dy = src.b_dy;
69 int RGBShiftConfig::equivalent(RGBShiftConfig &src)
71 return EQUIV(r_dx, src.r_dx) && EQUIV(g_dx, src.g_dx) && EQUIV(b_dx, src.b_dx) &&
72 EQUIV(r_dy, src.r_dy) && EQUIV(g_dy, src.g_dy) && EQUIV(b_dy, src.b_dy);
75 void RGBShiftConfig::interpolate(RGBShiftConfig &prev,
81 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
82 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
84 r_dx = prev.r_dx * prev_scale + next.r_dx * next_scale;
85 r_dy = prev.r_dy * prev_scale + next.r_dy * next_scale;
86 g_dx = prev.g_dx * prev_scale + next.g_dx * next_scale;
87 g_dy = prev.g_dy * prev_scale + next.g_dy * next_scale;
88 b_dx = prev.b_dx * prev_scale + next.b_dx * next_scale;
89 b_dy = prev.b_dy * prev_scale + next.b_dy * next_scale;
98 RGBShiftIText::RGBShiftIText(RGBShiftWindow *window, RGBShiftEffect *plugin,
99 RGBShiftISlider *slider, int *output, int x, int y, int min, int max)
100 : BC_TumbleTextBox(window, *output,
101 min, max, x, y, xS(60), 0)
103 this->window = window;
104 this->plugin = plugin;
105 this->output = output;
106 this->slider = slider;
112 RGBShiftIText::~RGBShiftIText()
116 int RGBShiftIText::handle_event()
118 *output = atoi(get_text());
119 if(*output > max) *output = max;
120 if(*output < min) *output = min;
121 slider->update(*output);
122 plugin->send_configure_change();
126 RGBShiftISlider::RGBShiftISlider(RGBShiftEffect *plugin, RGBShiftIText *text, int *output, int x, int y)
127 : BC_ISlider(x, y, 0, xS(200), xS(200), -MAXVALUE, MAXVALUE, *output)
129 this->plugin = plugin;
130 this->output = output;
132 enable_show_value(0); // Hide caption
135 int RGBShiftISlider::handle_event()
137 *output = get_value();
138 text->update((int64_t)*output);
139 plugin->send_configure_change();
144 RGBShiftReset::RGBShiftReset(RGBShiftEffect *plugin, RGBShiftWindow *window, int x, int y)
145 : BC_GenericButton(x, y, _("Reset"))
147 this->plugin = plugin;
148 this->window = window;
150 RGBShiftReset::~RGBShiftReset()
153 int RGBShiftReset::handle_event()
155 plugin->config.reset(RESET_ALL);
156 window->update_gui(RESET_ALL);
157 plugin->send_configure_change();
162 RGBShiftClr::RGBShiftClr(RGBShiftEffect *plugin, RGBShiftWindow *window, int x, int y, int clear)
163 : BC_Button(x, y, plugin->get_theme()->get_image_set("reset_button"))
165 this->plugin = plugin;
166 this->window = window;
169 RGBShiftClr::~RGBShiftClr()
172 int RGBShiftClr::handle_event()
174 // clear==1 ==> r_dx slider --- clear==2 ==> r_dy slider
175 // clear==3 ==> g_dx slider --- clear==4 ==> g_dy slider
176 // clear==5 ==> b_dx slider --- clear==6 ==> b_dy slider
177 plugin->config.reset(clear);
178 window->update_gui(clear);
179 plugin->send_configure_change();
184 RGBShiftWindow::RGBShiftWindow(RGBShiftEffect *plugin)
185 : PluginClientWindow(plugin, xS(420), yS(250), xS(420), yS(250), 0)
187 this->plugin = plugin;
190 void RGBShiftWindow::create_objects()
193 int ys10 = yS(10), ys30 = yS(30), ys40 = yS(40);
194 int x = xs10, y = ys10;
195 int x2 = xS(80), x3 = xS(180);
196 int clr_x = get_w()-x - xS(22); // note: clrBtn_w = 22
201 add_subwindow(new BC_Title(x, y, _("R_dx:")));
202 r_dx_text = new RGBShiftIText(this, plugin,
203 0, &plugin->config.r_dx, (x + x2), y, -MAXVALUE, MAXVALUE);
204 r_dx_text->create_objects();
205 r_dx_slider = new RGBShiftISlider(plugin,
206 r_dx_text, &plugin->config.r_dx, x3, y);
207 add_subwindow(r_dx_slider);
208 r_dx_text->slider = r_dx_slider;
209 clr_x = x3 + r_dx_slider->get_w() + x;
210 add_subwindow(r_dx_Clr = new RGBShiftClr(plugin, this, clr_x, y, RESET_R_DX));
213 add_subwindow(new BC_Title(x, y, _("R_dy:")));
214 r_dy_text = new RGBShiftIText(this, plugin,
215 0, &plugin->config.r_dy, (x + x2), y, -MAXVALUE, MAXVALUE);
216 r_dy_text->create_objects();
217 r_dy_slider = new RGBShiftISlider(plugin,
218 r_dy_text, &plugin->config.r_dy, x3, y);
219 add_subwindow(r_dy_slider);
220 r_dy_text->slider = r_dy_slider;
221 add_subwindow(r_dy_Clr = new RGBShiftClr(plugin, this, clr_x, y, RESET_R_DY));
224 add_subwindow(new BC_Title(x, y, _("G_dx:")));
225 g_dx_text = new RGBShiftIText(this, plugin,
226 0, &plugin->config.g_dx, (x + x2), y, -MAXVALUE, MAXVALUE);
227 g_dx_text->create_objects();
228 g_dx_slider = new RGBShiftISlider(plugin,
229 g_dx_text, &plugin->config.g_dx, x3, y);
230 add_subwindow(g_dx_slider);
231 g_dx_text->slider = g_dx_slider;
232 add_subwindow(g_dx_Clr = new RGBShiftClr(plugin, this, clr_x, y, RESET_G_DX));
235 add_subwindow(new BC_Title(x, y, _("G_dy:")));
236 g_dy_text = new RGBShiftIText(this, plugin,
237 0, &plugin->config.g_dy, (x + x2), y, -MAXVALUE, MAXVALUE);
238 g_dy_text->create_objects();
239 g_dy_slider = new RGBShiftISlider(plugin,
240 g_dy_text, &plugin->config.g_dy, x3, y);
241 add_subwindow(g_dy_slider);
242 g_dy_text->slider = g_dy_slider;
243 add_subwindow(g_dy_Clr = new RGBShiftClr(plugin, this, clr_x, y, RESET_G_DY));
246 add_subwindow(new BC_Title(x, y, _("B_dx:")));
247 b_dx_text = new RGBShiftIText(this, plugin,
248 0, &plugin->config.b_dx, (x + x2), y, -MAXVALUE, MAXVALUE);
249 b_dx_text->create_objects();
250 b_dx_slider = new RGBShiftISlider(plugin,
251 b_dx_text, &plugin->config.b_dx, x3, y);
252 add_subwindow(b_dx_slider);
253 b_dx_text->slider = b_dx_slider;
254 add_subwindow(b_dx_Clr = new RGBShiftClr(plugin, this, clr_x, y, RESET_B_DX));
257 add_subwindow(new BC_Title(x, y, _("B_dy:")));
258 b_dy_text = new RGBShiftIText(this, plugin,
259 0, &plugin->config.b_dy, (x + x2), y, -MAXVALUE, MAXVALUE);
260 b_dy_text->create_objects();
261 b_dy_slider = new RGBShiftISlider(plugin,
262 b_dy_text, &plugin->config.b_dy, x3, y);
263 add_subwindow(b_dy_slider);
264 b_dy_text->slider = b_dy_slider;
265 add_subwindow(b_dy_Clr = new RGBShiftClr(plugin, this, clr_x, y, RESET_B_DY));
269 add_subwindow(bar = new BC_Bar(x, y, get_w()-2*x));
271 add_subwindow(reset = new RGBShiftReset(plugin, this, x, y));
279 void RGBShiftWindow::update_gui(int clear)
283 r_dx_text->update((int64_t)plugin->config.r_dx);
284 r_dx_slider->update(plugin->config.r_dx);
287 r_dy_text->update((int64_t)plugin->config.r_dy);
288 r_dy_slider->update(plugin->config.r_dy);
291 g_dx_text->update((int64_t)plugin->config.g_dx);
292 g_dx_slider->update(plugin->config.g_dx);
295 g_dy_text->update((int64_t)plugin->config.g_dy);
296 g_dy_slider->update(plugin->config.g_dy);
299 b_dx_text->update((int64_t)plugin->config.b_dx);
300 b_dx_slider->update(plugin->config.b_dx);
303 b_dy_text->update((int64_t)plugin->config.b_dy);
304 b_dy_slider->update(plugin->config.b_dy);
308 r_dx_text->update((int64_t)plugin->config.r_dx);
309 r_dx_slider->update(plugin->config.r_dx);
310 r_dy_text->update((int64_t)plugin->config.r_dy);
311 r_dy_slider->update(plugin->config.r_dy);
312 g_dx_text->update((int64_t)plugin->config.g_dx);
313 g_dx_slider->update(plugin->config.g_dx);
314 g_dy_text->update((int64_t)plugin->config.g_dy);
315 g_dy_slider->update(plugin->config.g_dy);
316 b_dx_text->update((int64_t)plugin->config.b_dx);
317 b_dx_slider->update(plugin->config.b_dx);
318 b_dy_text->update((int64_t)plugin->config.b_dy);
319 b_dy_slider->update(plugin->config.b_dy);
329 RGBShiftEffect::RGBShiftEffect(PluginServer *server)
330 : PluginVClient(server)
334 RGBShiftEffect::~RGBShiftEffect()
339 const char* RGBShiftEffect::plugin_title() { return N_("RGBShift"); }
340 int RGBShiftEffect::is_realtime() { return 1; }
343 NEW_WINDOW_MACRO(RGBShiftEffect, RGBShiftWindow)
344 LOAD_CONFIGURATION_MACRO(RGBShiftEffect, RGBShiftConfig)
346 void RGBShiftEffect::update_gui()
350 RGBShiftWindow *yuv_wdw = (RGBShiftWindow*)thread->window;
351 yuv_wdw->lock_window("RGBShiftEffect::update_gui");
352 load_configuration();
353 yuv_wdw->r_dx_text->update((int64_t)config.r_dx);
354 yuv_wdw->r_dx_slider->update(config.r_dx);
355 yuv_wdw->r_dy_text->update((int64_t)config.r_dy);
356 yuv_wdw->r_dy_slider->update(config.r_dy);
357 yuv_wdw->g_dx_text->update((int64_t)config.g_dx);
358 yuv_wdw->g_dx_slider->update(config.g_dx);
359 yuv_wdw->g_dy_text->update((int64_t)config.g_dy);
360 yuv_wdw->g_dy_slider->update(config.g_dy);
361 yuv_wdw->b_dx_text->update((int64_t)config.b_dx);
362 yuv_wdw->b_dx_slider->update(config.b_dx);
363 yuv_wdw->b_dy_text->update((int64_t)config.b_dy);
364 yuv_wdw->b_dy_slider->update(config.b_dy);
365 yuv_wdw->unlock_window();
369 void RGBShiftEffect::save_data(KeyFrame *keyframe)
372 output.set_shared_output(keyframe->xbuf);
373 output.tag.set_title("RGBSHIFT");
374 output.tag.set_property("R_DX", config.r_dx);
375 output.tag.set_property("R_DY", config.r_dy);
376 output.tag.set_property("G_DX", config.g_dx);
377 output.tag.set_property("G_DY", config.g_dy);
378 output.tag.set_property("B_DX", config.b_dx);
379 output.tag.set_property("B_DY", config.b_dy);
381 output.tag.set_title("/RGBSHIFT");
383 output.append_newline();
384 output.terminate_string();
387 void RGBShiftEffect::read_data(KeyFrame *keyframe)
390 input.set_shared_input(keyframe->xbuf);
391 while(!input.read_tag())
393 if(input.tag.title_is("RGBSHIFT"))
395 config.r_dx = input.tag.get_property("R_DX", config.r_dx);
396 config.r_dy = input.tag.get_property("R_DY", config.r_dy);
397 config.g_dx = input.tag.get_property("G_DX", config.g_dx);
398 config.g_dy = input.tag.get_property("G_DY", config.g_dy);
399 config.b_dx = input.tag.get_property("B_DX", config.b_dx);
400 config.b_dy = input.tag.get_property("B_DY", config.b_dy);
405 #define RGB_MACRO(type, temp_type, components) \
407 for(int i = 0; i < h; i++) { \
408 int ri = i + config.r_dy, gi = i + config.g_dy, bi = i + config.b_dy; \
409 type *in_r = ri >= 0 && ri < h ? (type *)frame->get_rows()[ri] : 0; \
410 type *in_g = gi >= 0 && gi < h ? (type *)frame->get_rows()[gi] : 0; \
411 type *in_b = bi >= 0 && bi < h ? (type *)frame->get_rows()[bi] : 0; \
412 type *out_row = (type *)output->get_rows()[i]; \
413 for(int j = 0; j < w; j++) { \
414 int rj = j + config.r_dx, gj = j + config.g_dx, bj = j + config.b_dx; \
415 type *rp = in_r && rj >= 0 && rj < w ? in_r + rj*components: 0; \
416 type *gp = in_g && gj >= 0 && gj < w ? in_g + gj*components: 0; \
417 type *bp = in_b && bj >= 0 && bj < w ? in_b + bj*components: 0; \
418 out_row[0] = rp ? rp[0] : 0; \
419 out_row[1] = gp ? gp[1] : 0; \
420 out_row[2] = bp ? bp[2] : 0; \
421 out_row += components; \
426 #define YUV_MACRO(type, temp_type, components) \
428 for(int i = 0; i < h; i++) { \
429 int ri = i + config.r_dy, gi = i + config.g_dy, bi = i + config.b_dy; \
430 uint8_t *in_r = ri >= 0 && ri < h ? (uint8_t *)frame->get_rows()[ri] : 0; \
431 uint8_t *in_g = gi >= 0 && gi < h ? (uint8_t *)frame->get_rows()[gi] : 0; \
432 uint8_t *in_b = bi >= 0 && bi < h ? (uint8_t *)frame->get_rows()[bi] : 0; \
433 type *out_row = (type *)output->get_rows()[i]; \
434 for(int j = 0; j < w; j++) { \
435 int rj = j + config.r_dx, gj = j + config.g_dx, bj = j + config.b_dx; \
436 uint8_t *rp = in_r && rj >= 0 && rj < w ? in_r + rj*3: 0; \
437 uint8_t *gp = in_g && gj >= 0 && gj < w ? in_g + gj*3: 0; \
438 uint8_t *bp = in_b && bj >= 0 && bj < w ? in_b + bj*3: 0; \
440 temp_type r = rp ? rp[0] : 0; \
441 temp_type g = gp ? gp[1] : 0; \
442 temp_type b = bp ? bp[2] : 0; \
443 if( sizeof(type) == 4 ) \
444 YUV::yuv.rgb_to_yuv_f(r, g, b, y, u, v); \
445 else if( sizeof(type) == 2 ) \
446 YUV::yuv.rgb_to_yuv_16(r, g, b, y, u, v); \
448 YUV::yuv.rgb_to_yuv_8(r, g, b, y, u, v); \
452 out_row += components; \
457 int RGBShiftEffect::process_realtime(VFrame *input, VFrame *output)
459 load_configuration();
461 if( EQUIV(config.r_dx, 0) && EQUIV(config.g_dx, 0) && EQUIV(config.b_dx, 0) &&
462 EQUIV(config.r_dy, 0) && EQUIV(config.g_dy, 0) && EQUIV(config.b_dy, 0) ) {
463 if(input->get_rows()[0] != output->get_rows()[0])
464 output->copy_from(input);
468 int w = input->get_w(), h = input->get_h();
469 int color_model = input->get_color_model();
470 int is_yuv = BC_CModels::is_yuv(color_model);
471 if( is_yuv ) color_model = BC_RGB888;
472 VFrame *frame = input;
473 if( input->get_rows()[0] == output->get_rows()[0] || !is_yuv ) {
474 if( temp_frame && ( temp_frame->get_color_model() != color_model ||
475 temp_frame->get_w() != w || temp_frame->get_h() != h ) ) {
476 delete temp_frame; temp_frame = 0;
479 temp_frame = new VFrame(w, h, color_model, 0);
481 if( color_model != input->get_color_model() )
482 BC_CModels::transfer(frame->get_rows(), input->get_rows(),
483 frame->get_y(), frame->get_u(), frame->get_v(),
484 input->get_y(), input->get_u(), input->get_v(),
485 0, 0, input->get_w(), input->get_h(),
486 0, 0, frame->get_w(), frame->get_h(),
487 input->get_color_model(), frame->get_color_model(), 0,
488 input->get_bytes_per_line(), w);
490 frame->copy_from(input);
493 switch( input->get_color_model() ) {
494 case BC_YUV888: YUV_MACRO(unsigned char, int, 3); break;
495 case BC_YUV161616: YUV_MACRO(uint16_t, int, 3); break;
496 case BC_YUVA8888: YUV_MACRO(unsigned char, int, 4); break;
497 case BC_YUVA16161616: YUV_MACRO(uint16_t, int, 4); break;
498 case BC_RGB_FLOAT: RGB_MACRO(float, float, 3); break;
499 case BC_RGB888: RGB_MACRO(unsigned char, int, 3); break;
500 case BC_RGB161616: RGB_MACRO(uint16_t, int, 3); break;
501 case BC_RGBA_FLOAT: RGB_MACRO(float, float, 4); break;
502 case BC_RGBA8888: RGB_MACRO(unsigned char, int, 4); break;
503 case BC_RGBA16161616: RGB_MACRO(uint16_t, int, 4); break;