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
27 #include "bcdisplayinfo.h"
34 #include "overlayframe.h"
41 REGISTER_PLUGIN(GradientMain)
48 GradientConfig::GradientConfig()
53 void GradientConfig::reset()
67 shape = GradientConfig::LINEAR;
68 rate = GradientConfig::LINEAR;
73 int GradientConfig::equivalent(GradientConfig &that)
75 return (EQUIV(angle, that.angle) &&
76 EQUIV(in_radius, that.in_radius) &&
77 EQUIV(out_radius, that.out_radius) &&
82 out_r == that.out_r &&
83 out_g == that.out_g &&
84 out_b == that.out_b &&
85 out_a == that.out_a &&
86 shape == that.shape &&
88 EQUIV(center_x, that.center_x) &&
89 EQUIV(center_y, that.center_y));
92 void GradientConfig::copy_from(GradientConfig &that)
95 in_radius = that.in_radius;
96 out_radius = that.out_radius;
107 center_x = that.center_x;
108 center_y = that.center_y;
111 void GradientConfig::interpolate(GradientConfig &prev,
112 GradientConfig &next,
117 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
118 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
121 this->angle = (int)(prev.angle * prev_scale + next.angle * next_scale);
122 this->in_radius = (int)(prev.in_radius * prev_scale + next.in_radius * next_scale);
123 this->out_radius = (int)(prev.out_radius * prev_scale + next.out_radius * next_scale);
124 in_r = (int)(prev.in_r * prev_scale + next.in_r * next_scale);
125 in_g = (int)(prev.in_g * prev_scale + next.in_g * next_scale);
126 in_b = (int)(prev.in_b * prev_scale + next.in_b * next_scale);
127 in_a = (int)(prev.in_a * prev_scale + next.in_a * next_scale);
128 out_r = (int)(prev.out_r * prev_scale + next.out_r * next_scale);
129 out_g = (int)(prev.out_g * prev_scale + next.out_g * next_scale);
130 out_b = (int)(prev.out_b * prev_scale + next.out_b * next_scale);
131 out_a = (int)(prev.out_a * prev_scale + next.out_a * next_scale);
134 center_x = prev.center_x * prev_scale + next.center_x * next_scale;
135 center_y = prev.center_y * prev_scale + next.center_y * next_scale;
138 int GradientConfig::get_in_color()
140 int result = (in_r << 16) | (in_g << 8) | (in_b);
144 int GradientConfig::get_out_color()
146 int result = (out_r << 16) | (out_g << 8) | (out_b);
163 GradientWindow::GradientWindow(GradientMain *plugin)
164 : PluginClientWindow(plugin,
171 this->plugin = plugin;
180 GradientWindow::~GradientWindow()
182 delete in_color_thread;
183 delete out_color_thread;
186 void GradientWindow::create_objects()
188 int margin = plugin->get_theme()->widget_border;
192 add_subwindow(title = new BC_Title(x, y, _("Shape:")));
193 add_subwindow(shape = new GradientShape(plugin,
195 x + title->get_w() + margin,
197 shape->create_objects();
198 y += shape->get_h() + margin;
201 y += BC_Pot::calculate_h() + margin;
203 add_subwindow(title = new BC_Title(x, y, _("Rate:")));
204 add_subwindow(rate = new GradientRate(plugin,
205 x + title->get_w() + margin,
207 rate->create_objects();
208 y += rate->get_h() + margin;
214 add_subwindow(title1 = new BC_Title(x, y, _("Inner radius:")));
216 y += BC_Slider::get_span(0) + margin;
219 add_subwindow(title2 = new BC_Title(x, y, _("Outer radius:")));
221 add_subwindow(reset = new GradientReset(plugin, this, x, y+100));
224 x += MAX(title1->get_w(), title2->get_w()) + margin;
226 add_subwindow(in_radius = new GradientInRadius(plugin, x, y));
227 y += in_radius->get_h() + margin;
229 add_subwindow(out_radius = new GradientOutRadius(plugin, x, y));
230 y += out_radius->get_h() + margin;
234 add_subwindow(in_color = new GradientInColorButton(plugin, this, x, y));
235 y += COLOR_H + margin;
237 add_subwindow(out_color = new GradientOutColorButton(plugin, this, x, y));
238 x += MAX(in_color->get_w(), out_color->get_w()) + margin;
243 y += COLOR_H + margin;
246 in_color_thread = new GradientInColorThread(plugin, this);
247 out_color_thread = new GradientOutColorThread(plugin, this);
252 draw_3d_border(in_color_x - 2,
258 draw_3d_border(out_color_x - 2,
268 void GradientWindow::update_shape()
270 int x = shape_x, y = shape_y;
272 if(plugin->config.shape == GradientConfig::LINEAR)
274 delete center_x_title;
275 delete center_y_title;
285 add_subwindow(angle_title = new BC_Title(x, y, _("Angle:")));
286 add_subwindow(angle = new GradientAngle(plugin, x + angle_title->get_w() + 10, y));
297 add_subwindow(center_x_title = new BC_Title(x, y, _("Center X:")));
298 add_subwindow(center_x = new GradientCenterX(plugin,
299 x + center_x_title->get_w() + 10,
301 x += center_x_title->get_w() + 10 + center_x->get_w() + 10;
302 add_subwindow(center_y_title = new BC_Title(x, y, _("Center Y:")));
303 add_subwindow(center_y = new GradientCenterY(plugin,
304 x + center_y_title->get_w() + 10,
314 void GradientWindow::update_in_color()
316 //printf("GradientWindow::update_in_color 1 %08x\n", plugin->config.get_in_color());
317 set_color(plugin->config.get_in_color());
318 draw_box(in_color_x, in_color_y, COLOR_W, COLOR_H);
319 flash(in_color_x, in_color_y, COLOR_W, COLOR_H);
322 void GradientWindow::update_out_color()
324 //printf("GradientWindow::update_out_color 1 %08x\n", plugin->config.get_in_color());
325 set_color(plugin->config.get_out_color());
326 draw_box(out_color_x, out_color_y, COLOR_W, COLOR_H);
327 flash(out_color_x, out_color_y, COLOR_W, COLOR_H);
330 void GradientWindow::done_event(int result)
332 in_color_thread->close_window();
333 out_color_thread->close_window();
344 GradientShape::GradientShape(GradientMain *plugin,
348 : BC_PopupMenu(x, y, 100, to_text(plugin->config.shape), 1)
350 this->plugin = plugin;
353 void GradientShape::create_objects()
355 add_item(new BC_MenuItem(to_text(GradientConfig::LINEAR)));
356 add_item(new BC_MenuItem(to_text(GradientConfig::RADIAL)));
358 char* GradientShape::to_text(int shape)
362 case GradientConfig::LINEAR:
368 int GradientShape::from_text(char *text)
370 if(!strcmp(text, to_text(GradientConfig::LINEAR)))
371 return GradientConfig::LINEAR;
372 return GradientConfig::RADIAL;
374 int GradientShape::handle_event()
376 plugin->config.shape = from_text(get_text());
378 plugin->send_configure_change();
385 GradientCenterX::GradientCenterX(GradientMain *plugin, int x, int y)
386 : BC_FPot(x, y, plugin->config.center_x, 0, 100)
388 this->plugin = plugin;
390 int GradientCenterX::handle_event()
392 plugin->config.center_x = get_value();
393 plugin->send_configure_change();
399 GradientCenterY::GradientCenterY(GradientMain *plugin, int x, int y)
400 : BC_FPot(x, y, plugin->config.center_y, 0, 100)
402 this->plugin = plugin;
405 int GradientCenterY::handle_event()
407 plugin->config.center_y = get_value();
408 plugin->send_configure_change();
415 GradientAngle::GradientAngle(GradientMain *plugin, int x, int y)
418 plugin->config.angle,
422 this->plugin = plugin;
425 int GradientAngle::handle_event()
427 plugin->config.angle = get_value();
428 plugin->send_configure_change();
433 GradientRate::GradientRate(GradientMain *plugin, int x, int y)
437 to_text(plugin->config.rate),
440 this->plugin = plugin;
442 void GradientRate::create_objects()
444 add_item(new BC_MenuItem(to_text(GradientConfig::LINEAR)));
445 add_item(new BC_MenuItem(to_text(GradientConfig::LOG)));
446 add_item(new BC_MenuItem(to_text(GradientConfig::SQUARE)));
448 char* GradientRate::to_text(int shape)
452 case GradientConfig::LINEAR:
454 case GradientConfig::LOG:
460 int GradientRate::from_text(char *text)
462 if(!strcmp(text, to_text(GradientConfig::LINEAR)))
463 return GradientConfig::LINEAR;
464 if(!strcmp(text, to_text(GradientConfig::LOG)))
465 return GradientConfig::LOG;
466 return GradientConfig::SQUARE;
468 int GradientRate::handle_event()
470 plugin->config.rate = from_text(get_text());
471 plugin->send_configure_change();
477 GradientInRadius::GradientInRadius(GradientMain *plugin, int x, int y)
485 (float)plugin->config.in_radius)
487 this->plugin = plugin;
490 int GradientInRadius::handle_event()
492 plugin->config.in_radius = get_value();
493 plugin->send_configure_change();
498 GradientOutRadius::GradientOutRadius(GradientMain *plugin, int x, int y)
506 (float)plugin->config.out_radius)
508 this->plugin = plugin;
511 int GradientOutRadius::handle_event()
513 plugin->config.out_radius = get_value();
514 plugin->send_configure_change();
518 GradientInColorButton::GradientInColorButton(GradientMain *plugin, GradientWindow *window, int x, int y)
519 : BC_GenericButton(x, y, _("Inner color:"))
521 this->plugin = plugin;
522 this->window = window;
525 int GradientInColorButton::handle_event()
527 window->in_color_thread->start_window(
528 plugin->config.get_in_color(),
529 plugin->config.in_a);
534 GradientOutColorButton::GradientOutColorButton(GradientMain *plugin, GradientWindow *window, int x, int y)
535 : BC_GenericButton(x, y, _("Outer color:"))
537 this->plugin = plugin;
538 this->window = window;
541 int GradientOutColorButton::handle_event()
543 window->out_color_thread->start_window(
544 plugin->config.get_out_color(),
545 plugin->config.out_a);
549 GradientReset::GradientReset(GradientMain *plugin, GradientWindow *window, int x, int y)
550 : BC_GenericButton(x, y, _("Reset"))
552 this->plugin = plugin;
553 this->window = window;
556 int GradientReset::handle_event()
558 plugin->config.reset();
559 window->update_gui();
560 plugin->send_configure_change();
564 GradientInColorThread::GradientInColorThread(GradientMain *plugin,
565 GradientWindow *window)
566 : ColorPicker(1, _("Inner color"))
568 this->plugin = plugin;
569 this->window = window;
572 int GradientInColorThread::handle_new_color(int output, int alpha)
574 plugin->config.in_r = (output & 0xff0000) >> 16;
575 plugin->config.in_g = (output & 0xff00) >> 8;
576 plugin->config.in_b = (output & 0xff);
577 plugin->config.in_a = alpha;
579 window->lock_window("GradientInColorThread::handle_new_color");
580 window->update_in_color();
582 window->unlock_window();
583 plugin->send_configure_change();
584 // printf("GradientInColorThread::handle_event 1 %d %d %d %d %d %d %d %d\n",
585 // plugin->config.in_r,
586 // plugin->config.in_g,
587 // plugin->config.in_b,
588 // plugin->config.in_a,
589 // plugin->config.out_r,
590 // plugin->config.out_g,
591 // plugin->config.out_b,
592 // plugin->config.out_a);
599 GradientOutColorThread::GradientOutColorThread(GradientMain *plugin,
600 GradientWindow *window)
601 : ColorPicker(1, _("Outer color"))
603 this->plugin = plugin;
604 this->window = window;
607 int GradientOutColorThread::handle_new_color(int output, int alpha)
609 plugin->config.out_r = (output & 0xff0000) >> 16;
610 plugin->config.out_g = (output & 0xff00) >> 8;
611 plugin->config.out_b = (output & 0xff);
612 plugin->config.out_a = alpha;
613 window->lock_window("GradientOutColorThread::handle_new_color");
614 window->update_out_color();
616 window->unlock_window();
617 plugin->send_configure_change();
618 // printf("GradientOutColorThread::handle_event 1 %d %d %d %d %d %d %d %d\n",
619 // plugin->config.in_r,
620 // plugin->config.in_g,
621 // plugin->config.in_b,
622 // plugin->config.in_a,
623 // plugin->config.out_r,
624 // plugin->config.out_g,
625 // plugin->config.out_b,
626 // plugin->config.out_a);
641 GradientMain::GradientMain(PluginServer *server)
642 : PluginVClient(server)
645 need_reconfigure = 1;
651 GradientMain::~GradientMain()
655 if(gradient) delete gradient;
656 if(engine) delete engine;
657 if(overlayer) delete overlayer;
660 const char* GradientMain::plugin_title() { return N_("Gradient"); }
661 int GradientMain::is_realtime() { return 1; }
664 NEW_WINDOW_MACRO(GradientMain, GradientWindow)
666 LOAD_CONFIGURATION_MACRO(GradientMain, GradientConfig)
668 int GradientMain::is_synthesis()
674 int GradientMain::process_buffer(VFrame *frame,
675 int64_t start_position,
679 this->output = frame;
680 need_reconfigure |= load_configuration();
682 int need_alpha = config.in_a != 0xff || config.out_a != 0xff;
689 if(get_use_opengl()) return run_opengl();
691 int gradient_cmodel = input->get_color_model();
692 if(need_alpha && BC_CModels::components(gradient_cmodel) == 3)
694 switch(gradient_cmodel)
697 gradient_cmodel = BC_RGBA8888;
700 gradient_cmodel = BC_RGBA_FLOAT;
703 gradient_cmodel = BC_YUVA8888;
708 if(gradient && gradient->get_color_model() != gradient_cmodel)
715 gradient = new VFrame(input->get_w(), input->get_h(),
718 if(!engine) engine = new GradientServer(this,
719 get_project_smp() + 1,
720 get_project_smp() + 1);
721 engine->process_packages();
723 // Use overlay routine in GradientServer if mismatched colormodels
724 if(gradient->get_color_model() == output->get_color_model())
726 if(!overlayer) overlayer = new OverlayFrame(get_project_smp() + 1);
727 overlayer->overlay(output,
747 void GradientMain::update_gui()
749 if( !thread ) return;
750 if( !load_configuration() ) return;
751 ((GradientWindow*)thread->window)->lock_window("GradientMain::update_gui");
752 GradientWindow *window = (GradientWindow *)thread->window;
753 window->update_gui();
754 window->unlock_window();
757 void GradientWindow::update_gui()
759 GradientConfig &config = plugin->config;
760 rate->set_text(GradientRate::to_text(config.rate));
761 in_radius->update(config.in_radius);
762 out_radius->update(config.out_radius);
763 shape->set_text(GradientShape::to_text(config.shape));
764 if( angle ) angle->update(config.angle);
765 if( center_x ) center_x->update(config.center_x);
766 if( center_y ) center_y->update(config.center_y);
771 in_color_thread->update_gui(config.get_in_color(), config.in_a);
772 out_color_thread->update_gui(config.get_out_color(), config.out_a);
773 lock_window("GradientWindow::update_gui");
777 void GradientMain::save_data(KeyFrame *keyframe)
781 // cause data to be stored directly in text
782 output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
783 output.tag.set_title("GRADIENT");
785 output.tag.set_property("ANGLE", config.angle);
786 output.tag.set_property("IN_RADIUS", config.in_radius);
787 output.tag.set_property("OUT_RADIUS", config.out_radius);
788 output.tag.set_property("IN_R", config.in_r);
789 output.tag.set_property("IN_G", config.in_g);
790 output.tag.set_property("IN_B", config.in_b);
791 output.tag.set_property("IN_A", config.in_a);
792 output.tag.set_property("OUT_R", config.out_r);
793 output.tag.set_property("OUT_G", config.out_g);
794 output.tag.set_property("OUT_B", config.out_b);
795 output.tag.set_property("OUT_A", config.out_a);
796 output.tag.set_property("SHAPE", config.shape);
797 output.tag.set_property("RATE", config.rate);
798 output.tag.set_property("CENTER_X", config.center_x);
799 output.tag.set_property("CENTER_Y", config.center_y);
801 output.tag.set_title("/GRADIENT");
803 output.append_newline();
804 output.terminate_string();
807 void GradientMain::read_data(KeyFrame *keyframe)
811 input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
817 result = input.read_tag();
821 if(input.tag.title_is("GRADIENT"))
823 config.angle = input.tag.get_property("ANGLE", config.angle);
824 config.rate = input.tag.get_property("RATE", config.rate);
825 config.in_radius = input.tag.get_property("IN_RADIUS", config.in_radius);
826 config.out_radius = input.tag.get_property("OUT_RADIUS", config.out_radius);
827 config.in_r = input.tag.get_property("IN_R", config.in_r);
828 config.in_g = input.tag.get_property("IN_G", config.in_g);
829 config.in_b = input.tag.get_property("IN_B", config.in_b);
830 config.in_a = input.tag.get_property("IN_A", config.in_a);
831 config.out_r = input.tag.get_property("OUT_R", config.out_r);
832 config.out_g = input.tag.get_property("OUT_G", config.out_g);
833 config.out_b = input.tag.get_property("OUT_B", config.out_b);
834 config.out_a = input.tag.get_property("OUT_A", config.out_a);
835 config.shape = input.tag.get_property("SHAPE", config.shape);
836 config.center_x = input.tag.get_property("CENTER_X", config.center_x);
837 config.center_y = input.tag.get_property("CENTER_Y", config.center_y);
843 int GradientMain::handle_opengl()
846 const char *head_frag =
847 "uniform sampler2D tex;\n"
848 "uniform float half_w;\n"
849 "uniform float half_h;\n"
850 "uniform float center_x;\n"
851 "uniform float center_y;\n"
852 "uniform float half_gradient_size;\n"
853 "uniform float sin_angle;\n"
854 "uniform float cos_angle;\n"
855 "uniform vec4 out_color;\n"
856 "uniform vec4 in_color;\n"
857 "uniform float in_radius;\n"
858 "uniform float out_radius;\n"
859 "uniform float radius_diff;\n"
863 " vec2 out_coord = gl_TexCoord[0].st;\n";
865 const char *linear_shape =
866 " vec2 in_coord = vec2(out_coord.x - half_w, half_h - out_coord.y);\n"
867 " float mag = half_gradient_size - \n"
868 " (in_coord.x * sin_angle + in_coord.y * cos_angle);\n";
870 const char *radial_shape =
871 " vec2 in_coord = vec2(out_coord.x - center_x, out_coord.y - center_y);\n"
872 " float mag = length(vec2(in_coord.x, in_coord.y));\n";
874 // No clamp function in NVidia
875 const char *linear_rate =
876 " mag = min(max(mag, in_radius), out_radius);\n"
877 " float opacity = (mag - in_radius) / radius_diff;\n";
879 // NVidia warns about exp, but exp is in the GLSL spec.
880 const char *log_rate =
881 " mag = max(mag, in_radius);\n"
882 " float opacity = 1.0 - \n"
883 " exp(1.0 * -(mag - in_radius) / radius_diff);\n";
885 const char *square_rate =
886 " mag = min(max(mag, in_radius), out_radius);\n"
887 " float opacity = pow((mag - in_radius) / radius_diff, 2.0);\n"
888 " opacity = min(opacity, 1.0);\n";
890 const char *tail_frag =
891 " vec4 color = mix(in_color, out_color, opacity);\n"
892 " vec4 bg_color = texture2D(tex, out_coord);\n"
893 " gl_FragColor.rgb = mix(bg_color.rgb, color.rgb, color.a);\n"
894 " gl_FragColor.a = max(bg_color.a, color.a);\n"
898 const char *shader_stack[16];
899 memset(shader_stack,0, sizeof(shader_stack));
900 int current_shader = 0;
902 shader_stack[current_shader++] = head_frag;
904 const char *shape_frag = 0;
905 switch( config.shape ) {
906 case GradientConfig::LINEAR:
907 shape_frag = linear_shape;
910 shape_frag = radial_shape;
914 shader_stack[current_shader++] = shape_frag;
916 const char *rate_frag = 0;
917 switch(config.rate) {
918 case GradientConfig::LINEAR:
919 rate_frag = linear_rate;
921 case GradientConfig::LOG:
922 rate_frag = log_rate;
924 case GradientConfig::SQUARE:
925 rate_frag = square_rate;
929 shader_stack[current_shader++] = rate_frag;
931 shader_stack[current_shader++] = tail_frag;
933 // Force frame to create texture without copying to it if full alpha.
934 if( config.in_a >= 0xff && config.out_a >= 0xff )
935 get_output()->set_opengl_state(VFrame::TEXTURE);
936 get_output()->to_texture();
937 get_output()->enable_opengl();
938 get_output()->init_screen();
939 get_output()->bind_texture(0);
941 shader_stack[current_shader] = 0;
942 unsigned int shader = VFrame::make_shader(shader_stack);
944 glUseProgram(shader);
945 float w = get_output()->get_w();
946 float h = get_output()->get_h();
947 float texture_w = get_output()->get_texture_w();
948 float texture_h = get_output()->get_texture_h();
949 glUniform1i(glGetUniformLocation(shader, "tex"), 0);
950 glUniform1f(glGetUniformLocation(shader, "half_w"), w / 2 / texture_w);
951 glUniform1f(glGetUniformLocation(shader, "half_h"), h / 2 / texture_h);
952 if(config.shape == GradientConfig::LINEAR)
954 glUniform1f(glGetUniformLocation(shader, "center_x"),
956 glUniform1f(glGetUniformLocation(shader, "center_y"),
961 glUniform1f(glGetUniformLocation(shader, "center_x"),
962 (float)config.center_x * w / 100 / texture_w);
963 glUniform1f(glGetUniformLocation(shader, "center_y"),
964 (float)config.center_y * h / 100 / texture_h);
966 float gradient_size = hypotf(w / texture_w, h / texture_h);
967 glUniform1f(glGetUniformLocation(shader, "half_gradient_size"),
969 glUniform1f(glGetUniformLocation(shader, "sin_angle"),
970 sin(config.angle * (M_PI / 180)));
971 glUniform1f(glGetUniformLocation(shader, "cos_angle"),
972 cos(config.angle * (M_PI / 180)));
973 float in_radius = (float)config.in_radius / 100 * gradient_size;
974 glUniform1f(glGetUniformLocation(shader, "in_radius"), in_radius);
975 float out_radius = (float)config.out_radius / 100 * gradient_size;
976 glUniform1f(glGetUniformLocation(shader, "out_radius"), out_radius);
977 glUniform1f(glGetUniformLocation(shader, "radius_diff"),
978 out_radius - in_radius);
980 switch(get_output()->get_color_model()) {
983 float in1, in2, in3, in4;
984 float out1, out2, out3, out4;
985 YUV::yuv.rgb_to_yuv_f(
986 (float)config.in_r / 0xff,
987 (float)config.in_g / 0xff,
988 (float)config.in_b / 0xff,
990 in4 = (float)config.in_a / 0xff;
991 YUV::yuv.rgb_to_yuv_f(
992 (float)config.out_r / 0xff,
993 (float)config.out_g / 0xff,
994 (float)config.out_b / 0xff,
996 in2 += 0.5; in3 += 0.5;
997 out2 += 0.5; out3 += 0.5;
998 out4 = (float)config.out_a / 0xff;
999 glUniform4f(glGetUniformLocation(shader, "out_color"),
1000 out1, out2, out3, out4);
1001 glUniform4f(glGetUniformLocation(shader, "in_color"),
1002 in1, in2, in3, in4);
1006 glUniform4f(glGetUniformLocation(shader, "out_color"),
1007 (float)config.out_r / 0xff,
1008 (float)config.out_g / 0xff,
1009 (float)config.out_b / 0xff,
1010 (float)config.out_a / 0xff);
1011 glUniform4f(glGetUniformLocation(shader, "in_color"),
1012 (float)config.in_r / 0xff,
1013 (float)config.in_g / 0xff,
1014 (float)config.in_b / 0xff,
1015 (float)config.in_a / 0xff);
1020 get_output()->draw_texture();
1022 get_output()->set_opengl_state(VFrame::SCREEN);
1029 GradientPackage::GradientPackage()
1034 GradientUnit::GradientUnit(GradientServer *server, GradientMain *plugin)
1035 : LoadClient(server)
1037 this->plugin = plugin;
1038 this->server = server;
1042 static float calculate_opacity(float mag,
1043 float in_radius, float out_radius, int rate)
1045 float opacity = 0.0;
1048 case GradientConfig::LINEAR:
1052 if(mag >= out_radius)
1055 opacity = (float)(mag - in_radius) / (out_radius - in_radius);
1058 case GradientConfig::LOG:
1062 // Let this one decay beyond out_radius
1063 opacity = 1 - exp(1.0 * -(float)(mag - in_radius) /
1064 (out_radius - in_radius));
1067 case GradientConfig::SQUARE:
1071 if(mag >= out_radius)
1074 opacity = powf((float)(mag - in_radius) /
1075 (out_radius - in_radius), 2.0);
1078 CLAMP(opacity, 0.0, 1.0);
1082 #define CREATE_GRADIENT(type, temp, components, max) \
1084 /* Synthesize linear gradient for lookups */ \
1086 r_table = malloc(sizeof(type) * gradient_size); \
1087 g_table = malloc(sizeof(type) * gradient_size); \
1088 b_table = malloc(sizeof(type) * gradient_size); \
1089 a_table = malloc(sizeof(type) * gradient_size); \
1091 for(int i = 0; i < gradient_size; i++) \
1093 float opacity = calculate_opacity(i, in_radius, out_radius, plugin->config.rate); \
1094 float transparency; \
1096 transparency = 1.0 - opacity; \
1097 ((type*)r_table)[i] = (type)(out1 * opacity + in1 * transparency); \
1098 ((type*)g_table)[i] = (type)(out2 * opacity + in2 * transparency); \
1099 ((type*)b_table)[i] = (type)(out3 * opacity + in3 * transparency); \
1100 ((type*)a_table)[i] = (type)(out4 * opacity + in4 * transparency); \
1103 for(int i = pkg->y1; i < pkg->y2; i++) \
1105 type *gradient_row = (type*)plugin->gradient->get_rows()[i]; \
1106 type *out_row = (type*)plugin->get_output()->get_rows()[i]; \
1108 switch(plugin->config.shape) \
1110 case GradientConfig::LINEAR: \
1111 for(int j = 0; j < w; j++) \
1113 int x = j - half_w; \
1114 int y = -(i - half_h); \
1116 /* Rotate by effect angle */ \
1117 int mag = (int)(gradient_size / 2 - \
1118 (x * sin_angle + y * cos_angle) + \
1121 /* Get gradient value from these coords */ \
1123 if(sizeof(type) == 4) \
1125 float opacity = calculate_opacity(mag, \
1128 plugin->config.rate); \
1129 float transparency = 1.0 - opacity; \
1130 gradient_row[0] = (type)(out1 * opacity + in1 * transparency); \
1131 gradient_row[1] = (type)(out2 * opacity + in2 * transparency); \
1132 gradient_row[2] = (type)(out3 * opacity + in3 * transparency); \
1133 if(components == 4) gradient_row[3] = (type)(out4 * opacity + in4 * transparency); \
1138 gradient_row[0] = out1; \
1139 gradient_row[1] = out2; \
1140 gradient_row[2] = out3; \
1141 if(components == 4) gradient_row[3] = out4; \
1144 if(mag >= gradient_size) \
1146 gradient_row[0] = in1; \
1147 gradient_row[1] = in2; \
1148 gradient_row[2] = in3; \
1149 if(components == 4) gradient_row[3] = in4; \
1153 gradient_row[0] = ((type*)r_table)[mag]; \
1154 gradient_row[1] = ((type*)g_table)[mag]; \
1155 gradient_row[2] = ((type*)b_table)[mag]; \
1156 if(components == 4) gradient_row[3] = ((type*)a_table)[mag]; \
1159 /* Overlay mixed colormodels onto output */ \
1160 if(gradient_cmodel != output_cmodel) \
1162 temp opacity = gradient_row[3]; \
1163 temp transparency = max - opacity; \
1164 out_row[0] = (transparency * out_row[0] + opacity * gradient_row[0]) / max; \
1165 out_row[1] = (transparency * out_row[1] + opacity * gradient_row[1]) / max; \
1166 out_row[2] = (transparency * out_row[2] + opacity * gradient_row[2]) / max; \
1170 gradient_row += components; \
1174 case GradientConfig::RADIAL: \
1175 for(int j = 0; j < w; j++) \
1177 double x = j - center_x; \
1178 double y = i - center_y; \
1179 double magnitude = hypot(x, y); \
1180 int mag = (int)magnitude; \
1181 if(sizeof(type) == 4) \
1183 float opacity = calculate_opacity(mag, \
1186 plugin->config.rate); \
1187 float transparency = 1.0 - opacity; \
1188 gradient_row[0] = (type)(out1 * opacity + in1 * transparency); \
1189 gradient_row[1] = (type)(out2 * opacity + in2 * transparency); \
1190 gradient_row[2] = (type)(out3 * opacity + in3 * transparency); \
1191 if(components == 4) gradient_row[3] = (type)(out4 * opacity + in4 * transparency); \
1195 gradient_row[0] = ((type*)r_table)[mag]; \
1196 gradient_row[1] = ((type*)g_table)[mag]; \
1197 gradient_row[2] = ((type*)b_table)[mag]; \
1198 if(components == 4) gradient_row[3] = ((type*)a_table)[mag]; \
1201 /* Overlay mixed colormodels onto output */ \
1202 if(gradient_cmodel != output_cmodel) \
1204 temp opacity = gradient_row[3]; \
1205 temp transparency = max - opacity; \
1206 out_row[0] = (transparency * out_row[0] + opacity * gradient_row[0]) / max; \
1207 out_row[1] = (transparency * out_row[1] + opacity * gradient_row[1]) / max; \
1208 out_row[2] = (transparency * out_row[2] + opacity * gradient_row[2]) / max; \
1212 gradient_row += components; \
1219 void GradientUnit::process_package(LoadPackage *package)
1221 GradientPackage *pkg = (GradientPackage*)package;
1222 int h = plugin->input->get_h();
1223 int w = plugin->input->get_w();
1226 int gradient_size = (int)(ceil(hypot(w, h)));
1227 int in_radius = (int)(plugin->config.in_radius / 100 * gradient_size);
1228 int out_radius = (int)(plugin->config.out_radius / 100 * gradient_size);
1229 double sin_angle = sin(plugin->config.angle * (M_PI / 180));
1230 double cos_angle = cos(plugin->config.angle * (M_PI / 180));
1231 double center_x = plugin->config.center_x * w / 100;
1232 double center_y = plugin->config.center_y * h / 100;
1237 int gradient_cmodel = plugin->gradient->get_color_model();
1238 int output_cmodel = plugin->get_output()->get_color_model();
1240 if(in_radius > out_radius)
1242 in_radius ^= out_radius;
1243 out_radius ^= in_radius;
1244 in_radius ^= out_radius;
1248 switch(gradient_cmodel)
1252 int in1 = plugin->config.in_r;
1253 int in2 = plugin->config.in_g;
1254 int in3 = plugin->config.in_b;
1255 int in4 = plugin->config.in_a;
1256 int out1 = plugin->config.out_r;
1257 int out2 = plugin->config.out_g;
1258 int out3 = plugin->config.out_b;
1259 int out4 = plugin->config.out_a;
1260 CREATE_GRADIENT(unsigned char, int, 3, 0xff)
1266 int in1 = plugin->config.in_r;
1267 int in2 = plugin->config.in_g;
1268 int in3 = plugin->config.in_b;
1269 int in4 = plugin->config.in_a;
1270 int out1 = plugin->config.out_r;
1271 int out2 = plugin->config.out_g;
1272 int out3 = plugin->config.out_b;
1273 int out4 = plugin->config.out_a;
1274 CREATE_GRADIENT(unsigned char, int, 4, 0xff)
1280 float in1 = (float)plugin->config.in_r / 0xff;
1281 float in2 = (float)plugin->config.in_g / 0xff;
1282 float in3 = (float)plugin->config.in_b / 0xff;
1283 float in4 = (float)plugin->config.in_a / 0xff;
1284 float out1 = (float)plugin->config.out_r / 0xff;
1285 float out2 = (float)plugin->config.out_g / 0xff;
1286 float out3 = (float)plugin->config.out_b / 0xff;
1287 float out4 = (float)plugin->config.out_a / 0xff;
1288 CREATE_GRADIENT(float, float, 3, 1.0)
1294 float in1 = (float)plugin->config.in_r / 0xff;
1295 float in2 = (float)plugin->config.in_g / 0xff;
1296 float in3 = (float)plugin->config.in_b / 0xff;
1297 float in4 = (float)plugin->config.in_a / 0xff;
1298 float out1 = (float)plugin->config.out_r / 0xff;
1299 float out2 = (float)plugin->config.out_g / 0xff;
1300 float out3 = (float)plugin->config.out_b / 0xff;
1301 float out4 = (float)plugin->config.out_a / 0xff;
1302 CREATE_GRADIENT(float, float, 4, 1.0)
1308 int in1, in2, in3, in4;
1309 int out1, out2, out3, out4;
1310 YUV::yuv.rgb_to_yuv_8(plugin->config.in_r,
1311 plugin->config.in_g,
1312 plugin->config.in_b,
1316 in4 = plugin->config.in_a;
1317 YUV::yuv.rgb_to_yuv_8(plugin->config.out_r,
1318 plugin->config.out_g,
1319 plugin->config.out_b,
1323 out4 = plugin->config.out_a;
1324 CREATE_GRADIENT(unsigned char, int, 3, 0xff)
1330 int in1, in2, in3, in4;
1331 int out1, out2, out3, out4;
1332 YUV::yuv.rgb_to_yuv_8(plugin->config.in_r,
1333 plugin->config.in_g,
1334 plugin->config.in_b,
1338 in4 = plugin->config.in_a;
1339 YUV::yuv.rgb_to_yuv_8(plugin->config.out_r,
1340 plugin->config.out_g,
1341 plugin->config.out_b,
1345 out4 = plugin->config.out_a;
1346 CREATE_GRADIENT(unsigned char, int, 4, 0xff)
1351 if(r_table) free(r_table);
1352 if(g_table) free(g_table);
1353 if(b_table) free(b_table);
1354 if(a_table) free(a_table);
1362 GradientServer::GradientServer(GradientMain *plugin,
1365 : LoadServer(total_clients, total_packages)
1367 this->plugin = plugin;
1370 void GradientServer::init_packages()
1372 for(int i = 0; i < get_total_packages(); i++)
1374 GradientPackage *package = (GradientPackage*)get_package(i);
1375 package->y1 = plugin->input->get_h() *
1377 get_total_packages();
1378 package->y2 = plugin->input->get_h() *
1380 get_total_packages();
1384 LoadClient* GradientServer::new_client()
1386 return new GradientUnit(this, plugin);
1389 LoadPackage* GradientServer::new_package()
1391 return new GradientPackage;