1 #include "bcdisplayinfo.h"
7 #include "loadbalance.h"
9 #include "plugincolors.h"
10 #include "playback3d.h"
11 #include "pluginvclient.h"
22 #define MINSATURATION -100
23 #define MAXSATURATION 100
37 void copy_from(HueConfig &src);
38 int equivalent(HueConfig &src);
39 void interpolate(HueConfig &prev,
44 float hue, saturation, value;
47 class HueSlider : public BC_FSlider
50 HueSlider(HueEffect *plugin, int x, int y, int w);
55 class SaturationSlider : public BC_FSlider
58 SaturationSlider(HueEffect *plugin, int x, int y, int w);
62 char string[BCTEXTLEN];
65 class ValueSlider : public BC_FSlider
68 ValueSlider(HueEffect *plugin, int x, int y, int w);
72 char string[BCTEXTLEN];
75 class HueWindow : public BC_Window
78 HueWindow(HueEffect *plugin, int x, int y);
79 void create_objects();
83 SaturationSlider *saturation;
87 PLUGIN_THREAD_HEADER(HueEffect, HueThread, HueWindow)
89 class HueEngine : public LoadServer
92 HueEngine(HueEffect *plugin, int cpus);
94 LoadClient* new_client();
95 LoadPackage* new_package();
99 class HuePackage : public LoadPackage
106 class HueUnit : public LoadClient
109 HueUnit(HueEffect *plugin, HueEngine *server);
110 void process_package(LoadPackage *package);
115 class HueEffect : public PluginVClient
118 HueEffect(PluginServer *server);
121 int process_buffer(VFrame *frame,
122 int64_t start_position,
125 char* plugin_title();
127 int load_configuration();
130 void save_data(KeyFrame *keyframe);
131 void read_data(KeyFrame *keyframe);
139 VFrame *input, *output;
164 HueConfig::HueConfig()
166 hue = saturation = value = 0;
169 void HueConfig::copy_from(HueConfig &src)
172 saturation = src.saturation;
175 int HueConfig::equivalent(HueConfig &src)
177 return EQUIV(hue, src.hue) &&
178 EQUIV(saturation, src.saturation) &&
179 EQUIV(value, src.value);
181 void HueConfig::interpolate(HueConfig &prev,
187 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
188 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
190 this->hue = prev.hue * prev_scale + next.hue * next_scale;
191 this->saturation = prev.saturation * prev_scale + next.saturation * next_scale;
192 this->value = prev.value * prev_scale + next.value * next_scale;
202 HueSlider::HueSlider(HueEffect *plugin, int x, int y, int w)
212 this->plugin = plugin;
214 int HueSlider::handle_event()
216 plugin->config.hue = get_value();
217 plugin->send_configure_change();
227 SaturationSlider::SaturationSlider(HueEffect *plugin, int x, int y, int w)
233 (float)MINSATURATION,
234 (float)MAXSATURATION,
235 plugin->config.saturation)
237 this->plugin = plugin;
239 int SaturationSlider::handle_event()
241 plugin->config.saturation = get_value();
242 plugin->send_configure_change();
246 char* SaturationSlider::get_caption()
248 float fraction = ((float)plugin->config.saturation - MINSATURATION) /
250 sprintf(string, "%0.4f", fraction);
260 ValueSlider::ValueSlider(HueEffect *plugin, int x, int y, int w)
268 plugin->config.value)
270 this->plugin = plugin;
272 int ValueSlider::handle_event()
274 plugin->config.value = get_value();
275 plugin->send_configure_change();
279 char* ValueSlider::get_caption()
281 float fraction = ((float)plugin->config.value - MINVALUE) / MAXVALUE;
282 sprintf(string, "%0.4f", fraction);
292 HueWindow::HueWindow(HueEffect *plugin, int x, int y)
293 : BC_Window(plugin->gui_string,
304 this->plugin = plugin;
306 void HueWindow::create_objects()
308 int x = 10, y = 10, x1 = 100;
309 add_subwindow(new BC_Title(x, y, _("Hue:")));
310 add_subwindow(hue = new HueSlider(plugin, x1, y, 200));
312 add_subwindow(new BC_Title(x, y, _("Saturation:")));
313 add_subwindow(saturation = new SaturationSlider(plugin, x1, y, 200));
315 add_subwindow(new BC_Title(x, y, _("Value:")));
316 add_subwindow(value = new ValueSlider(plugin, x1, y, 200));
322 WINDOW_CLOSE_EVENT(HueWindow)
331 PLUGIN_THREAD_OBJECT(HueEffect, HueThread, HueWindow)
333 HueEngine::HueEngine(HueEffect *plugin, int cpus)
334 : LoadServer(cpus, cpus)
336 this->plugin = plugin;
338 void HueEngine::init_packages()
340 for(int i = 0; i < LoadServer::get_total_packages(); i++)
342 HuePackage *pkg = (HuePackage*)get_package(i);
343 pkg->row1 = plugin->input->get_h() * i / LoadServer::get_total_packages();
344 pkg->row2 = plugin->input->get_h() * (i + 1) / LoadServer::get_total_packages();
347 LoadClient* HueEngine::new_client()
349 return new HueUnit(plugin, this);
351 LoadPackage* HueEngine::new_package()
353 return new HuePackage;
363 HuePackage::HuePackage()
368 HueUnit::HueUnit(HueEffect *plugin, HueEngine *server)
371 this->plugin = plugin;
380 #define HUESATURATION(type, max, components, use_yuv) \
382 float h_offset = plugin->config.hue; \
383 float s_offset = ((float)plugin->config.saturation - MINSATURATION) / MAXSATURATION; \
384 float v_offset = ((float)plugin->config.value - MINVALUE) / MAXVALUE; \
385 for(int i = pkg->row1; i < pkg->row2; i++) \
387 type* in_row = (type*)plugin->input->get_rows()[i]; \
388 type* out_row = (type*)plugin->output->get_rows()[i]; \
390 for(int j = 0; j < w; j++) \
399 y = (int)in_row[0]; \
400 u = (int)in_row[1]; \
401 v = (int)in_row[2]; \
403 yuv.yuv_to_rgb_16(r_i, g_i, b_i, y, u, v); \
405 yuv.yuv_to_rgb_8(r_i, g_i, b_i, y, u, v); \
406 HSV::rgb_to_hsv((float)r_i / max, \
415 r = (float)in_row[0] / max; \
416 g = (float)in_row[1] / max; \
417 b = (float)in_row[2] / max; \
418 HSV::rgb_to_hsv(r, g, b, h, s, va); \
426 if(h >= 360) h -= 360; \
427 if(h < 0) h += 360; \
428 if(sizeof(type) < 4) \
438 HSV::hsv_to_yuv(y, u, v, h, s, va, max); \
445 HSV::hsv_to_rgb(r, g, b, h, s, va); \
446 if(sizeof(type) < 4) \
451 out_row[0] = (type)CLIP(r, 0, max); \
452 out_row[1] = (type)CLIP(g, 0, max); \
453 out_row[2] = (type)CLIP(b, 0, max); \
457 out_row[0] = (type)r; \
458 out_row[1] = (type)g; \
459 out_row[2] = (type)b; \
463 in_row += components; \
464 out_row += components; \
470 void HueUnit::process_package(LoadPackage *package)
472 HuePackage *pkg = (HuePackage*)package;
473 int w = plugin->input->get_w();
475 switch(plugin->input->get_color_model())
478 HUESATURATION(unsigned char, 0xff, 3, 0)
482 HUESATURATION(float, 1, 3, 0)
486 HUESATURATION(unsigned char, 0xff, 3, 1)
490 HUESATURATION(uint16_t, 0xffff, 3, 0)
494 HUESATURATION(uint16_t, 0xffff, 3, 1)
498 HUESATURATION(float, 1, 4, 0)
502 HUESATURATION(unsigned char, 0xff, 4, 0)
506 HUESATURATION(unsigned char, 0xff, 4, 1)
509 case BC_RGBA16161616:
510 HUESATURATION(uint16_t, 0xffff, 4, 0)
513 case BC_YUVA16161616:
514 HUESATURATION(uint16_t, 0xffff, 4, 1)
523 REGISTER_PLUGIN(HueEffect)
526 HueEffect::HueEffect(PluginServer *server)
527 : PluginVClient(server)
530 PLUGIN_CONSTRUCTOR_MACRO
532 HueEffect::~HueEffect()
534 PLUGIN_DESTRUCTOR_MACRO
535 if(engine) delete engine;
538 int HueEffect::process_buffer(VFrame *frame,
539 int64_t start_position,
542 load_configuration();
552 this->output = frame;
553 if(EQUIV(config.hue, 0) && EQUIV(config.saturation, 0) && EQUIV(config.value, 0))
565 if(!engine) engine = new HueEngine(this, PluginClient::smp + 1);
567 engine->process_packages();
572 char* HueEffect::plugin_title() { return N_("Hue saturation"); }
573 int HueEffect::is_realtime() { return 1; }
575 NEW_PICON_MACRO(HueEffect)
576 SHOW_GUI_MACRO(HueEffect, HueThread)
577 SET_STRING_MACRO(HueEffect)
578 RAISE_WINDOW_MACRO(HueEffect)
579 LOAD_CONFIGURATION_MACRO(HueEffect, HueConfig)
581 int HueEffect::load_defaults()
583 char directory[BCTEXTLEN];
584 sprintf(directory, "%shuesaturation.rc", BCASTDIR);
585 defaults = new BC_Hash(directory);
587 config.hue = defaults->get("HUE", config.hue);
588 config.saturation = defaults->get("SATURATION", config.saturation);
589 config.value = defaults->get("VALUE", config.value);
592 int HueEffect::save_defaults()
594 defaults->update("HUE", config.hue);
595 defaults->update("SATURATION", config.saturation);
596 defaults->update("VALUE", config.value);
600 void HueEffect::save_data(KeyFrame *keyframe)
603 output.set_shared_string(keyframe->data, MESSAGESIZE);
604 output.tag.set_title("HUESATURATION");
605 output.tag.set_property("HUE", config.hue);
606 output.tag.set_property("SATURATION", config.saturation);
607 output.tag.set_property("VALUE", config.value);
609 output.terminate_string();
611 void HueEffect::read_data(KeyFrame *keyframe)
614 input.set_shared_string(keyframe->data, strlen(keyframe->data));
615 while(!input.read_tag())
617 if(input.tag.title_is("HUESATURATION"))
619 config.hue = input.tag.get_property("HUE", config.hue);
620 config.saturation = input.tag.get_property("SATURATION", config.saturation);
621 config.value = input.tag.get_property("VALUE", config.value);
625 void HueEffect::update_gui()
629 thread->window->lock_window();
630 load_configuration();
631 thread->window->hue->update(config.hue);
632 thread->window->saturation->update(config.saturation);
633 thread->window->value->update(config.value);
634 thread->window->unlock_window();
638 int HueEffect::handle_opengl()
641 static char *yuv_saturation_frag =
642 "uniform sampler2D tex;\n"
643 "uniform float s_offset;\n"
644 "uniform float v_offset;\n"
647 " vec4 pixel = texture2D(tex, gl_TexCoord[0].st);\n"
648 " pixel.r *= v_offset;\n"
649 " pixel.gb -= vec2(0.5, 0.5);\n"
650 " pixel.g *= s_offset;\n"
651 " pixel.b *= s_offset;\n"
652 " pixel.gb += vec2(0.5, 0.5);\n"
653 " gl_FragColor = pixel;\n"
657 static char *yuv_frag =
658 "uniform sampler2D tex;\n"
659 "uniform float h_offset;\n"
660 "uniform float s_offset;\n"
661 "uniform float v_offset;\n"
664 " vec4 pixel = texture2D(tex, gl_TexCoord[0].st);\n"
665 YUV_TO_RGB_FRAG("pixel")
666 RGB_TO_HSV_FRAG("pixel")
667 " pixel.r += h_offset;\n"
668 " pixel.g *= s_offset;\n"
669 " pixel.b *= v_offset;\n"
670 " if(pixel.r >= 360.0) pixel.r -= 360.0;\n"
671 " if(pixel.r < 0.0) pixel.r += 360.0;\n"
672 HSV_TO_RGB_FRAG("pixel")
673 RGB_TO_YUV_FRAG("pixel")
674 " gl_FragColor = pixel;\n"
677 static char *rgb_frag =
678 "uniform sampler2D tex;\n"
679 "uniform float h_offset;\n"
680 "uniform float s_offset;\n"
681 "uniform float v_offset;\n"
684 " vec4 pixel = texture2D(tex, gl_TexCoord[0].st);\n"
685 RGB_TO_HSV_FRAG("pixel")
686 " pixel.r += h_offset;\n"
687 " pixel.g *= s_offset;\n"
688 " pixel.b *= v_offset;\n"
689 " if(pixel.r >= 360.0) pixel.r -= 360.0;\n"
690 " if(pixel.r < 0.0) pixel.r += 360.0;\n"
691 HSV_TO_RGB_FRAG("pixel")
692 " gl_FragColor = pixel;\n"
696 get_output()->to_texture();
697 get_output()->enable_opengl();
699 unsigned int frag_shader = 0;
700 switch(get_output()->get_color_model())
704 // This is a lousy approximation but good enough for the masker.
705 if(EQUIV(config.hue, 0))
706 frag_shader = VFrame::make_shader(0,
710 frag_shader = VFrame::make_shader(0,
715 frag_shader = VFrame::make_shader(0,
724 glUseProgram(frag_shader);
725 glUniform1i(glGetUniformLocation(frag_shader, "tex"), 0);
726 glUniform1f(glGetUniformLocation(frag_shader, "h_offset"), config.hue);
727 glUniform1f(glGetUniformLocation(frag_shader, "s_offset"),
728 ((float)config.saturation - MINSATURATION) / MAXSATURATION);
729 glUniform1f(glGetUniformLocation(frag_shader, "v_offset"),
730 ((float)config.value - MINVALUE) / MAXVALUE);
733 get_output()->init_screen();
734 get_output()->bind_texture(0);
735 get_output()->draw_texture();
737 get_output()->set_opengl_state(VFrame::SCREEN);