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
23 #include "bcdisplayinfo.h"
27 #include "huesaturation.h"
30 #include "loadbalance.h"
32 #include "playback3d.h"
33 #include "pluginvclient.h"
41 REGISTER_PLUGIN(HueEffect)
47 HueConfig::HueConfig()
52 void HueConfig::reset()
54 hue = saturation = value = 0;
57 void HueConfig::copy_from(HueConfig &src)
60 saturation = src.saturation;
63 int HueConfig::equivalent(HueConfig &src)
65 return EQUIV(hue, src.hue) &&
66 EQUIV(saturation, src.saturation) &&
67 EQUIV(value, src.value);
69 void HueConfig::interpolate(HueConfig &prev,
75 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
76 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
78 this->hue = prev.hue * prev_scale + next.hue * next_scale;
79 this->saturation = prev.saturation * prev_scale + next.saturation * next_scale;
80 this->value = prev.value * prev_scale + next.value * next_scale;
90 HueSlider::HueSlider(HueEffect *plugin, int x, int y, int w)
100 this->plugin = plugin;
102 int HueSlider::handle_event()
104 plugin->config.hue = get_value();
105 plugin->send_configure_change();
115 SaturationSlider::SaturationSlider(HueEffect *plugin, int x, int y, int w)
121 (float)MINSATURATION,
122 (float)MAXSATURATION,
123 plugin->config.saturation)
125 this->plugin = plugin;
127 int SaturationSlider::handle_event()
129 plugin->config.saturation = get_value();
130 plugin->send_configure_change();
134 char* SaturationSlider::get_caption()
136 float fraction = ((float)plugin->config.saturation - MINSATURATION) /
138 sprintf(string, "%0.4f", fraction);
148 ValueSlider::ValueSlider(HueEffect *plugin, int x, int y, int w)
156 plugin->config.value)
158 this->plugin = plugin;
160 int ValueSlider::handle_event()
162 plugin->config.value = get_value();
163 plugin->send_configure_change();
167 char* ValueSlider::get_caption()
169 float fraction = ((float)plugin->config.value - MINVALUE) / MAXVALUE;
170 sprintf(string, "%0.4f", fraction);
175 HueReset::HueReset(HueEffect *plugin, HueWindow *gui, int x, int y)
176 : BC_GenericButton(x, y, _("Reset"))
178 this->plugin = plugin;
181 HueReset::~HueReset()
184 int HueReset::handle_event()
186 plugin->config.reset();
188 plugin->send_configure_change();
195 HueWindow::HueWindow(HueEffect *plugin)
196 : PluginClientWindow(plugin, 345, 145, 345, 145, 0)
198 this->plugin = plugin;
200 void HueWindow::create_objects()
202 int x = 10, y = 10, x1 = 100;
203 add_subwindow(new BC_Title(x, y, _("Hue:")));
204 add_subwindow(hue = new HueSlider(plugin, x1, y, 200));
206 add_subwindow(new BC_Title(x, y, _("Saturation:")));
207 add_subwindow(saturation = new SaturationSlider(plugin, x1, y, 200));
209 add_subwindow(new BC_Title(x, y, _("Value:")));
210 add_subwindow(value = new ValueSlider(plugin, x1, y, 200));
212 add_subwindow(reset = new HueReset(plugin, this, x, y));
219 void HueWindow::update()
221 hue->update(plugin->config.hue);
222 saturation->update(plugin->config.saturation);
223 value->update(plugin->config.value);
233 HueEngine::HueEngine(HueEffect *plugin, int cpus)
234 : LoadServer(cpus, cpus)
236 this->plugin = plugin;
238 void HueEngine::init_packages()
240 for(int i = 0; i < LoadServer::get_total_packages(); i++)
242 HuePackage *pkg = (HuePackage*)get_package(i);
243 pkg->row1 = plugin->input->get_h() * i / LoadServer::get_total_packages();
244 pkg->row2 = plugin->input->get_h() * (i + 1) / LoadServer::get_total_packages();
247 LoadClient* HueEngine::new_client()
249 return new HueUnit(plugin, this);
251 LoadPackage* HueEngine::new_package()
253 return new HuePackage;
263 HuePackage::HuePackage()
268 HueUnit::HueUnit(HueEffect *plugin, HueEngine *server)
271 this->plugin = plugin;
280 #define HUESATURATION(type, max, components, use_yuv) \
282 float h_offset = plugin->config.hue; \
283 float s_offset = ((float)plugin->config.saturation - MINSATURATION) / MAXSATURATION; \
284 float v_offset = ((float)plugin->config.value - MINVALUE) / MAXVALUE; \
285 for(int i = pkg->row1; i < pkg->row2; i++) \
287 type* in_row = (type*)plugin->input->get_rows()[i]; \
288 type* out_row = (type*)plugin->output->get_rows()[i]; \
290 for(int j = 0; j < w; j++) \
299 y = (int)in_row[0]; \
300 u = (int)in_row[1]; \
301 v = (int)in_row[2]; \
303 YUV::yuv.yuv_to_rgb_16(r_i, g_i, b_i, y, u, v); \
305 YUV::yuv.yuv_to_rgb_8(r_i, g_i, b_i, y, u, v); \
306 HSV::rgb_to_hsv((float)r_i / max, \
315 r = (float)in_row[0] / max; \
316 g = (float)in_row[1] / max; \
317 b = (float)in_row[2] / max; \
318 HSV::rgb_to_hsv(r, g, b, h, s, va); \
326 if(h >= 360) h -= 360; \
327 if(h < 0) h += 360; \
328 if(sizeof(type) < 4) \
338 HSV::hsv_to_yuv(y, u, v, h, s, va, max); \
345 HSV::hsv_to_rgb(r, g, b, h, s, va); \
346 if(sizeof(type) < 4) \
351 out_row[0] = (type)CLIP(r, 0, max); \
352 out_row[1] = (type)CLIP(g, 0, max); \
353 out_row[2] = (type)CLIP(b, 0, max); \
357 out_row[0] = (type)r; \
358 out_row[1] = (type)g; \
359 out_row[2] = (type)b; \
363 in_row += components; \
364 out_row += components; \
370 void HueUnit::process_package(LoadPackage *package)
372 HuePackage *pkg = (HuePackage*)package;
373 int w = plugin->input->get_w();
375 switch(plugin->input->get_color_model())
378 HUESATURATION(unsigned char, 0xff, 3, 0)
382 HUESATURATION(float, 1, 3, 0)
386 HUESATURATION(unsigned char, 0xff, 3, 1)
390 HUESATURATION(uint16_t, 0xffff, 3, 0)
394 HUESATURATION(uint16_t, 0xffff, 3, 1)
398 HUESATURATION(float, 1, 4, 0)
402 HUESATURATION(unsigned char, 0xff, 4, 0)
406 HUESATURATION(unsigned char, 0xff, 4, 1)
409 case BC_RGBA16161616:
410 HUESATURATION(uint16_t, 0xffff, 4, 0)
413 case BC_YUVA16161616:
414 HUESATURATION(uint16_t, 0xffff, 4, 1)
425 HueEffect::HueEffect(PluginServer *server)
426 : PluginVClient(server)
431 HueEffect::~HueEffect()
434 if(engine) delete engine;
437 int HueEffect::process_buffer(VFrame *frame,
438 int64_t start_position,
441 load_configuration();
451 this->output = frame;
452 if(EQUIV(config.hue, 0) && EQUIV(config.saturation, 0) && EQUIV(config.value, 0))
464 if(!engine) engine = new HueEngine(this, PluginClient::smp + 1);
466 engine->process_packages();
471 const char* HueEffect::plugin_title() { return N_("Hue saturation"); }
472 int HueEffect::is_realtime() { return 1; }
474 NEW_WINDOW_MACRO(HueEffect, HueWindow)
475 LOAD_CONFIGURATION_MACRO(HueEffect, HueConfig)
478 void HueEffect::save_data(KeyFrame *keyframe)
481 output.set_shared_output(keyframe->xbuf);
482 output.tag.set_title("HUESATURATION");
483 output.tag.set_property("HUE", config.hue);
484 output.tag.set_property("SATURATION", config.saturation);
485 output.tag.set_property("VALUE", config.value);
487 output.tag.set_title("/HUESATURATION");
489 output.append_newline();
490 output.terminate_string();
492 void HueEffect::read_data(KeyFrame *keyframe)
495 input.set_shared_input(keyframe->xbuf);
496 while(!input.read_tag())
498 if(input.tag.title_is("HUESATURATION"))
500 config.hue = input.tag.get_property("HUE", config.hue);
501 config.saturation = input.tag.get_property("SATURATION", config.saturation);
502 config.value = input.tag.get_property("VALUE", config.value);
506 void HueEffect::update_gui()
510 ((HueWindow*)thread->window)->lock_window();
511 load_configuration();
512 ((HueWindow*)thread->window)->hue->update(config.hue);
513 ((HueWindow*)thread->window)->saturation->update(config.saturation);
514 ((HueWindow*)thread->window)->value->update(config.value);
515 ((HueWindow*)thread->window)->unlock_window();
519 int HueEffect::handle_opengl()
522 const char *yuv_saturation_frag =
523 "uniform sampler2D tex;\n"
524 "uniform float s_offset;\n"
525 "uniform float v_offset;\n"
528 " vec4 pixel = texture2D(tex, gl_TexCoord[0].st);\n"
529 " pixel.r *= v_offset;\n"
530 " pixel.gb -= vec2(0.5, 0.5);\n"
531 " pixel.g *= s_offset;\n"
532 " pixel.b *= s_offset;\n"
533 " pixel.gb += vec2(0.5, 0.5);\n"
534 " gl_FragColor = pixel;\n"
538 const char *yuv_frag =
539 "uniform sampler2D tex;\n"
540 "uniform float h_offset;\n"
541 "uniform float s_offset;\n"
542 "uniform float v_offset;\n"
545 " vec4 pixel = texture2D(tex, gl_TexCoord[0].st);\n"
546 YUV_TO_RGB_FRAG("pixel")
547 RGB_TO_HSV_FRAG("pixel")
548 " pixel.r += h_offset;\n"
549 " pixel.g *= s_offset;\n"
550 " pixel.b *= v_offset;\n"
551 " if(pixel.r >= 360.0) pixel.r -= 360.0;\n"
552 " if(pixel.r < 0.0) pixel.r += 360.0;\n"
553 HSV_TO_RGB_FRAG("pixel")
554 RGB_TO_YUV_FRAG("pixel")
555 " gl_FragColor = pixel;\n"
558 const char *rgb_frag =
559 "uniform sampler2D tex;\n"
560 "uniform float h_offset;\n"
561 "uniform float s_offset;\n"
562 "uniform float v_offset;\n"
565 " vec4 pixel = texture2D(tex, gl_TexCoord[0].st);\n"
566 RGB_TO_HSV_FRAG("pixel")
567 " pixel.r += h_offset;\n"
568 " pixel.g *= s_offset;\n"
569 " pixel.b *= v_offset;\n"
570 " if(pixel.r >= 360.0) pixel.r -= 360.0;\n"
571 " if(pixel.r < 0.0) pixel.r += 360.0;\n"
572 HSV_TO_RGB_FRAG("pixel")
573 " gl_FragColor = pixel;\n"
577 get_output()->to_texture();
578 get_output()->enable_opengl();
580 const char *shader_stack[16];
581 memset(shader_stack,0, sizeof(shader_stack));
582 int current_shader = 0;
584 int need_color_matrix = BC_CModels::is_yuv(get_output()->get_color_model()) ? 1 : 0;
585 if( need_color_matrix ) shader_stack[current_shader++] = bc_gl_colors;
586 shader_stack[current_shader++] = !need_color_matrix ? rgb_frag :
587 EQUIV(config.hue, 0) ? yuv_saturation_frag: yuv_frag ;
589 shader_stack[current_shader] = 0;
590 unsigned int shader = VFrame::make_shader(shader_stack);
592 glUseProgram(shader);
593 glUniform1i(glGetUniformLocation(shader, "tex"), 0);
594 glUniform1f(glGetUniformLocation(shader, "h_offset"), config.hue);
595 glUniform1f(glGetUniformLocation(shader, "s_offset"),
596 ((float)config.saturation - MINSATURATION) / MAXSATURATION);
597 glUniform1f(glGetUniformLocation(shader, "v_offset"),
598 ((float)config.value - MINVALUE) / MAXVALUE);
599 if( need_color_matrix ) BC_GL_COLORS(shader);
602 get_output()->init_screen();
603 get_output()->bind_texture(0);
604 get_output()->draw_texture();
606 get_output()->set_opengl_state(VFrame::SCREEN);