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"
38 REGISTER_PLUGIN(GradientMain)
40 GradientConfig::GradientConfig()
45 void GradientConfig::reset()
50 in_r = in_g = in_b = in_a = 0xff;
51 out_r = out_g = out_b = out_a = 0x00;
52 shape = GradientConfig::LINEAR;
53 rate = GradientConfig::LINEAR;
58 int GradientConfig::equivalent(GradientConfig &that)
60 return (EQUIV(angle, that.angle) &&
61 EQUIV(in_radius, that.in_radius) &&
62 EQUIV(out_radius, that.out_radius) &&
67 out_r == that.out_r &&
68 out_g == that.out_g &&
69 out_b == that.out_b &&
70 out_a == that.out_a &&
71 shape == that.shape &&
73 EQUIV(center_x, that.center_x) &&
74 EQUIV(center_y, that.center_y));
77 void GradientConfig::copy_from(GradientConfig &that)
80 in_radius = that.in_radius;
81 out_radius = that.out_radius;
92 center_x = that.center_x;
93 center_y = that.center_y;
96 void GradientConfig::interpolate(GradientConfig &prev, GradientConfig &next,
97 long prev_frame, long next_frame, long current_frame)
99 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
100 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
102 this->angle = (int)(prev.angle * prev_scale + next.angle * next_scale);
103 this->in_radius = (int)(prev.in_radius * prev_scale + next.in_radius * next_scale);
104 this->out_radius = (int)(prev.out_radius * prev_scale + next.out_radius * next_scale);
105 in_r = (int)(prev.in_r * prev_scale + next.in_r * next_scale);
106 in_g = (int)(prev.in_g * prev_scale + next.in_g * next_scale);
107 in_b = (int)(prev.in_b * prev_scale + next.in_b * next_scale);
108 in_a = (int)(prev.in_a * prev_scale + next.in_a * next_scale);
109 out_r = (int)(prev.out_r * prev_scale + next.out_r * next_scale);
110 out_g = (int)(prev.out_g * prev_scale + next.out_g * next_scale);
111 out_b = (int)(prev.out_b * prev_scale + next.out_b * next_scale);
112 out_a = (int)(prev.out_a * prev_scale + next.out_a * next_scale);
115 center_x = prev.center_x * prev_scale + next.center_x * next_scale;
116 center_y = prev.center_y * prev_scale + next.center_y * next_scale;
119 int GradientConfig::get_in_color()
121 int result = (in_r << 16) | (in_g << 8) | (in_b);
125 int GradientConfig::get_out_color()
127 int result = (out_r << 16) | (out_g << 8) | (out_b);
134 GradientWindow::GradientWindow(GradientMain *plugin)
135 : PluginClientWindow(plugin, 350, 290, 350, 290, 0)
137 this->plugin = plugin;
145 out_color_thread = 0;
147 GradientWindow::~GradientWindow()
149 delete in_color_thread;
150 delete out_color_thread;
154 void GradientWindow::create_objects()
156 int margin = plugin->get_theme()->widget_border;
160 add_subwindow(title = new BC_Title(x, y, _("Shape:")));
161 add_subwindow(shape = new GradientShape(plugin, this,
162 x + title->get_w() + margin, y));
163 shape->create_objects();
164 y += shape->get_h() + margin;
167 y += BC_Pot::calculate_h() + margin;
169 add_subwindow(title = new BC_Title(x, y, _("Rate:")));
170 add_subwindow(rate = new GradientRate(plugin,
171 x + title->get_w() + margin, y));
172 rate->create_objects();
173 y += rate->get_h() + margin;
177 add_subwindow(title1 = new BC_Title(x, y, _("Inner radius:")));
178 y += BC_Slider::get_span(0) + margin;
180 add_subwindow(title2 = new BC_Title(x, y, _("Outer radius:")));
182 add_subwindow(reset = new GradientReset(plugin, this, x, y+100));
185 x += MAX(title1->get_w(), title2->get_w()) + margin;
186 add_subwindow(in_radius = new GradientInRadius(plugin, x, y));
187 y += in_radius->get_h() + margin;
188 add_subwindow(out_radius = new GradientOutRadius(plugin, x, y));
189 y += out_radius->get_h() + margin;
193 add_subwindow(in_color = new GradientInColorButton(plugin, this, x, y));
194 y += COLOR_H + margin;
196 add_subwindow(out_color = new GradientOutColorButton(plugin, this, x, y));
197 x += MAX(in_color->get_w(), out_color->get_w()) + margin;
202 y += COLOR_H + margin;
205 in_color_thread = new GradientInColorThread(plugin, this);
206 out_color_thread = new GradientOutColorThread(plugin, this);
211 draw_3d_border(in_color_x - 2, in_color_y - 2,
212 COLOR_W + 4, COLOR_H + 4, 1);
214 draw_3d_border(out_color_x - 2, out_color_y - 2,
215 COLOR_W + 4, COLOR_H + 4, 1);
219 void GradientWindow::update_shape()
221 int x = shape_x, y = shape_y;
223 if( plugin->config.shape == GradientConfig::LINEAR ) {
224 delete center_x_title; center_x_title = 0;
225 delete center_y_title; center_y_title = 0;
226 delete center_x; center_x = 0;
227 delete center_y; center_y = 0;
229 add_subwindow(angle_title = new BC_Title(x, y, _("Angle:")));
230 add_subwindow(angle = new GradientAngle(plugin, x + angle_title->get_w() + 10, y));
234 delete angle_title; angle_title = 0;
235 delete angle; angle = 0;
237 add_subwindow(center_x_title = new BC_Title(x, y, _("Center X:")));
238 add_subwindow(center_x = new GradientCenterX(plugin,
239 x + center_x_title->get_w() + 10, y));
240 x += center_x_title->get_w() + 10 + center_x->get_w() + 10;
241 add_subwindow(center_y_title = new BC_Title(x, y, _("Center Y:")));
242 add_subwindow(center_y = new GradientCenterY(plugin,
243 x + center_y_title->get_w() + 10, y));
249 void GradientWindow::update_in_color()
251 //printf("GradientWindow::update_in_color 1 %08x\n", plugin->config.get_in_color());
252 set_color(plugin->config.get_in_color());
253 draw_box(in_color_x, in_color_y, COLOR_W, COLOR_H);
254 flash(in_color_x, in_color_y, COLOR_W, COLOR_H);
257 void GradientWindow::update_out_color()
259 //printf("GradientWindow::update_out_color 1 %08x\n", plugin->config.get_in_color());
260 set_color(plugin->config.get_out_color());
261 draw_box(out_color_x, out_color_y, COLOR_W, COLOR_H);
262 flash(out_color_x, out_color_y, COLOR_W, COLOR_H);
265 void GradientWindow::done_event(int result)
267 in_color_thread->close_window();
268 out_color_thread->close_window();
271 GradientShape::GradientShape(GradientMain *plugin, GradientWindow *gui, int x, int y)
272 : BC_PopupMenu(x, y, 100, to_text(plugin->config.shape), 1)
274 this->plugin = plugin;
277 void GradientShape::create_objects()
279 add_item(new BC_MenuItem(to_text(GradientConfig::LINEAR)));
280 add_item(new BC_MenuItem(to_text(GradientConfig::RADIAL)));
282 char* GradientShape::to_text(int shape)
285 case GradientConfig::LINEAR: return _("Linear");
289 int GradientShape::from_text(char *text)
291 if( !strcmp(text, to_text(GradientConfig::LINEAR)) )
292 return GradientConfig::LINEAR;
293 return GradientConfig::RADIAL;
295 int GradientShape::handle_event()
297 plugin->config.shape = from_text(get_text());
299 plugin->send_configure_change();
304 GradientCenterX::GradientCenterX(GradientMain *plugin, int x, int y)
305 : BC_FPot(x, y, plugin->config.center_x, 0, 100)
307 this->plugin = plugin;
309 int GradientCenterX::handle_event()
311 plugin->config.center_x = get_value();
312 plugin->send_configure_change();
317 GradientCenterY::GradientCenterY(GradientMain *plugin, int x, int y)
318 : BC_FPot(x, y, plugin->config.center_y, 0, 100)
320 this->plugin = plugin;
323 int GradientCenterY::handle_event()
325 plugin->config.center_y = get_value();
326 plugin->send_configure_change();
331 GradientAngle::GradientAngle(GradientMain *plugin, int x, int y)
332 : BC_FPot(x, y, plugin->config.angle, -180, 180)
334 this->plugin = plugin;
337 int GradientAngle::handle_event()
339 plugin->config.angle = get_value();
340 plugin->send_configure_change();
345 GradientRate::GradientRate(GradientMain *plugin, int x, int y)
346 : BC_PopupMenu(x, y, 100, to_text(plugin->config.rate), 1)
348 this->plugin = plugin;
350 void GradientRate::create_objects()
352 add_item(new BC_MenuItem(to_text(GradientConfig::LINEAR)));
353 add_item(new BC_MenuItem(to_text(GradientConfig::LOG)));
354 add_item(new BC_MenuItem(to_text(GradientConfig::SQUARE)));
356 char* GradientRate::to_text(int shape)
359 case GradientConfig::LINEAR: return _("Linear");
360 case GradientConfig::LOG: return _("Log");
364 int GradientRate::from_text(char *text)
366 if( !strcmp(text, to_text(GradientConfig::LINEAR)) )
367 return GradientConfig::LINEAR;
368 if( !strcmp(text, to_text(GradientConfig::LOG)) )
369 return GradientConfig::LOG;
370 return GradientConfig::SQUARE;
372 int GradientRate::handle_event()
374 plugin->config.rate = from_text(get_text());
375 plugin->send_configure_change();
380 GradientInRadius::GradientInRadius(GradientMain *plugin, int x, int y)
381 : BC_FSlider(x, y, 0, 200, 200,
382 0.f, 100.f, (float)plugin->config.in_radius)
384 this->plugin = plugin;
387 int GradientInRadius::handle_event()
389 plugin->config.in_radius = get_value();
390 plugin->send_configure_change();
395 GradientOutRadius::GradientOutRadius(GradientMain *plugin, int x, int y)
396 : BC_FSlider(x, y, 0, 200, 200,
397 0.f, 100.f, (float)plugin->config.out_radius)
399 this->plugin = plugin;
402 int GradientOutRadius::handle_event()
404 plugin->config.out_radius = get_value();
405 plugin->send_configure_change();
409 GradientInColorButton::GradientInColorButton(GradientMain *plugin, GradientWindow *window, int x, int y)
410 : BC_GenericButton(x, y, _("Inner color:"))
412 this->plugin = plugin;
413 this->window = window;
416 int GradientInColorButton::handle_event()
418 window->in_color_thread->start_window(
419 plugin->config.get_in_color(),
420 plugin->config.in_a);
425 GradientOutColorButton::GradientOutColorButton(GradientMain *plugin, GradientWindow *window, int x, int y)
426 : BC_GenericButton(x, y, _("Outer color:"))
428 this->plugin = plugin;
429 this->window = window;
432 int GradientOutColorButton::handle_event()
434 window->out_color_thread->start_window(
435 plugin->config.get_out_color(),
436 plugin->config.out_a);
440 GradientReset::GradientReset(GradientMain *plugin, GradientWindow *window, int x, int y)
441 : BC_GenericButton(x, y, _("Reset"))
443 this->plugin = plugin;
444 this->window = window;
447 int GradientReset::handle_event()
449 plugin->config.reset();
450 window->update_gui();
451 plugin->send_configure_change();
455 GradientInColorThread::GradientInColorThread(GradientMain *plugin,
456 GradientWindow *window)
457 : ColorPicker(1, _("Inner color"))
459 this->plugin = plugin;
460 this->window = window;
463 int GradientInColorThread::handle_new_color(int output, int alpha)
465 plugin->config.in_r = (output & 0xff0000) >> 16;
466 plugin->config.in_g = (output & 0xff00) >> 8;
467 plugin->config.in_b = (output & 0xff);
468 plugin->config.in_a = alpha;
470 window->lock_window("GradientInColorThread::handle_new_color");
471 window->update_in_color();
473 window->unlock_window();
474 plugin->send_configure_change();
475 //printf("GradientInColorThread::handle_event 1 %d %d %d %d %d %d %d %d\n",
476 // plugin->config.in_r, plugin->config.in_g, plugin->config.in_b, plugin->config.in_a,
477 // plugin->config.out_r, plugin->config.out_g, plugin->config.out_b, plugin->config.out_a);
482 GradientOutColorThread::GradientOutColorThread(GradientMain *plugin,
483 GradientWindow *window)
484 : ColorPicker(1, _("Outer color"))
486 this->plugin = plugin;
487 this->window = window;
490 int GradientOutColorThread::handle_new_color(int output, int alpha)
492 plugin->config.out_r = (output & 0xff0000) >> 16;
493 plugin->config.out_g = (output & 0xff00) >> 8;
494 plugin->config.out_b = (output & 0xff);
495 plugin->config.out_a = alpha;
496 window->lock_window("GradientOutColorThread::handle_new_color");
497 window->update_out_color();
499 window->unlock_window();
500 plugin->send_configure_change();
501 //printf("GradientOutColorThread::handle_event 1 %d %d %d %d %d %d %d %d\n",
502 // plugin->config.in_r, plugin->config.in_g, plugin->config.in_b, plugin->config.in_a,
503 // plugin->config.out_r, plugin->config.out_g, plugin->config.out_b, plugin->config.out_a);
508 GradientMain::GradientMain(PluginServer *server)
509 : PluginVClient(server)
512 need_reconfigure = 1;
520 GradientMain::~GradientMain()
528 const char* GradientMain::plugin_title() { return N_("Gradient"); }
529 int GradientMain::is_realtime() { return 1; }
532 NEW_WINDOW_MACRO(GradientMain, GradientWindow)
534 LOAD_CONFIGURATION_MACRO(GradientMain, GradientConfig)
536 int GradientMain::is_synthesis()
542 int GradientMain::process_buffer(VFrame *frame,
543 int64_t start_position,
547 this->output = frame;
548 float fw = input->get_w(), fh = input->get_h();
549 gradient_size = hypotf(fw, fh);
550 need_reconfigure = load_configuration();
552 int need_alpha = config.in_a != 0xff || config.out_a != 0xff;
554 read_frame(frame, 0, start_position, frame_rate, get_use_opengl());
555 if( get_use_opengl() ) return run_opengl();
557 int gradient_cmodel = input->get_color_model();
558 if( need_alpha && BC_CModels::components(gradient_cmodel) == 3 ) {
559 switch( gradient_cmodel ) {
560 case BC_RGB888: gradient_cmodel = BC_RGBA8888; break;
561 case BC_YUV888: gradient_cmodel = BC_YUVA8888; break;
562 case BC_RGB_FLOAT: gradient_cmodel = BC_RGBA_FLOAT; break;
566 int bpp = BC_CModels::calculate_pixelsize(gradient_cmodel);
567 int comps = BC_CModels::components(gradient_cmodel);
568 int grad_size1 = gradient_size + 1;
569 int sz = 4 * (bpp / comps) * grad_size1;
570 if( table_size < sz ) {
571 delete [] table; table = 0;
574 table = new uint8_t[table_size = sz];
575 need_reconfigure = 1;
578 if( gradient && gradient->get_color_model() != gradient_cmodel ) {
584 gradient = new VFrame(input->get_w(), input->get_h(),
588 engine = new GradientServer(this,
589 get_project_smp() + 1, get_project_smp() + 1);
590 engine->process_packages();
592 // Use overlay routine in GradientServer if mismatched colormodels
593 if( gradient->get_color_model() == output->get_color_model() ) {
594 if( !overlayer ) overlayer = new OverlayFrame(get_project_smp() + 1);
595 overlayer->overlay(output, gradient,
596 0, 0, input->get_w(), input->get_h(),
597 0, 0, input->get_w(), input->get_h(),
598 1.0, TRANSFER_NORMAL, NEAREST_NEIGHBOR);
605 void GradientMain::update_gui()
607 if( !thread ) return;
608 if( !load_configuration() ) return;
609 ((GradientWindow*)thread->window)->lock_window("GradientMain::update_gui");
610 GradientWindow *window = (GradientWindow *)thread->window;
611 window->update_gui();
612 window->unlock_window();
615 void GradientWindow::update_gui()
617 GradientConfig &config = plugin->config;
618 rate->set_text(GradientRate::to_text(config.rate));
619 in_radius->update(config.in_radius);
620 out_radius->update(config.out_radius);
621 shape->set_text(GradientShape::to_text(config.shape));
622 if( angle ) angle->update(config.angle);
623 if( center_x ) center_x->update(config.center_x);
624 if( center_y ) center_y->update(config.center_y);
629 in_color_thread->update_gui(config.get_in_color(), config.in_a);
630 out_color_thread->update_gui(config.get_out_color(), config.out_a);
631 lock_window("GradientWindow::update_gui");
635 void GradientMain::save_data(KeyFrame *keyframe)
639 // cause data to be stored directly in text
640 output.set_shared_output(keyframe->xbuf);
641 output.tag.set_title("GRADIENT");
643 output.tag.set_property("ANGLE", config.angle);
644 output.tag.set_property("IN_RADIUS", config.in_radius);
645 output.tag.set_property("OUT_RADIUS", config.out_radius);
646 output.tag.set_property("IN_R", config.in_r);
647 output.tag.set_property("IN_G", config.in_g);
648 output.tag.set_property("IN_B", config.in_b);
649 output.tag.set_property("IN_A", config.in_a);
650 output.tag.set_property("OUT_R", config.out_r);
651 output.tag.set_property("OUT_G", config.out_g);
652 output.tag.set_property("OUT_B", config.out_b);
653 output.tag.set_property("OUT_A", config.out_a);
654 output.tag.set_property("SHAPE", config.shape);
655 output.tag.set_property("RATE", config.rate);
656 output.tag.set_property("CENTER_X", config.center_x);
657 output.tag.set_property("CENTER_Y", config.center_y);
659 output.tag.set_title("/GRADIENT");
661 output.append_newline();
662 output.terminate_string();
665 void GradientMain::read_data(KeyFrame *keyframe)
669 input.set_shared_input(keyframe->xbuf);
673 while( !(result = input.read_tag()) ) {
674 if( input.tag.title_is("GRADIENT") ) {
675 config.angle = input.tag.get_property("ANGLE", config.angle);
676 config.rate = input.tag.get_property("RATE", config.rate);
677 config.in_radius = input.tag.get_property("IN_RADIUS", config.in_radius);
678 config.out_radius = input.tag.get_property("OUT_RADIUS", config.out_radius);
679 config.in_r = input.tag.get_property("IN_R", config.in_r);
680 config.in_g = input.tag.get_property("IN_G", config.in_g);
681 config.in_b = input.tag.get_property("IN_B", config.in_b);
682 config.in_a = input.tag.get_property("IN_A", config.in_a);
683 config.out_r = input.tag.get_property("OUT_R", config.out_r);
684 config.out_g = input.tag.get_property("OUT_G", config.out_g);
685 config.out_b = input.tag.get_property("OUT_B", config.out_b);
686 config.out_a = input.tag.get_property("OUT_A", config.out_a);
687 config.shape = input.tag.get_property("SHAPE", config.shape);
688 config.center_x = input.tag.get_property("CENTER_X", config.center_x);
689 config.center_y = input.tag.get_property("CENTER_Y", config.center_y);
694 int GradientMain::handle_opengl()
697 const char *head_frag =
698 "uniform sampler2D tex;\n"
699 "uniform vec2 tex_dimensions;\n"
700 "uniform vec2 center;\n"
701 "uniform vec2 angle;\n"
702 "uniform float gradient_size;\n"
703 "uniform vec4 out_color;\n"
704 "uniform vec4 in_color;\n"
705 "uniform float in_radius;\n"
706 "uniform float out_radius;\n"
707 "uniform float radius_diff;\n"
711 " vec2 out_coord = gl_TexCoord[0].st;\n"
712 " vec2 in_coord = out_coord * tex_dimensions - center;\n";
714 const char *linear_shape =
715 " float mag = 0.5 + dot(in_coord,angle)/gradient_size;\n";
717 const char *radial_shape =
718 " float mag = length(in_coord)/gradient_size;\n";
720 // No clamp function in NVidia
721 const char *linear_rate =
722 " mag = min(max(mag, in_radius), out_radius);\n"
723 " float opacity = (mag - in_radius) / radius_diff;\n";
725 // NVidia warns about exp, but exp is in the GLSL spec.
726 const char *log_rate =
727 " mag = max(mag, in_radius);\n"
728 " float opacity = 1.0 - \n"
729 " exp(1.0 * -(mag - in_radius) / radius_diff);\n";
731 const char *square_rate =
732 " mag = min(max(mag, in_radius), out_radius);\n"
733 " float opacity = pow((mag - in_radius) / radius_diff, 2.0);\n"
734 " opacity = min(opacity, 1.0);\n";
736 const char *tail_frag =
737 " vec4 color = mix(in_color, out_color, opacity);\n"
738 " vec4 bg_color = texture2D(tex, out_coord);\n"
739 " gl_FragColor.rgb = mix(bg_color.rgb, color.rgb, color.a);\n"
740 " gl_FragColor.a = mix(bg_color.a, 1., color.a);\n"
744 const char *shader_stack[16];
745 memset(shader_stack,0, sizeof(shader_stack));
746 int current_shader = 0;
748 shader_stack[current_shader++] = head_frag;
750 const char *shape_frag = 0;
751 switch( config.shape ) {
752 case GradientConfig::LINEAR:
753 shape_frag = linear_shape;
756 shape_frag = radial_shape;
760 shader_stack[current_shader++] = shape_frag;
762 const char *rate_frag = 0;
763 switch( config.rate ) {
764 case GradientConfig::LINEAR:
765 rate_frag = linear_rate;
767 case GradientConfig::LOG:
768 rate_frag = log_rate;
770 case GradientConfig::SQUARE:
771 rate_frag = square_rate;
775 shader_stack[current_shader++] = rate_frag;
777 shader_stack[current_shader++] = tail_frag;
779 // Force frame to create texture without copying to it if full alpha.
780 if( config.in_a >= 0xff && config.out_a >= 0xff )
781 get_output()->set_opengl_state(VFrame::TEXTURE);
782 get_output()->to_texture();
783 get_output()->enable_opengl();
784 get_output()->init_screen();
785 get_output()->bind_texture(0);
787 shader_stack[current_shader] = 0;
788 unsigned int shader = VFrame::make_shader(shader_stack);
790 glUseProgram(shader);
791 float w = get_output()->get_w();
792 float h = get_output()->get_h();
793 glUniform1i(glGetUniformLocation(shader, "tex"), 0);
794 float texture_w = get_output()->get_texture_w();
795 float texture_h = get_output()->get_texture_h();
796 glUniform2f(glGetUniformLocation(shader, "tex_dimensions"),
797 texture_w, texture_h);
798 float u = config.shape == GradientConfig::LINEAR ?
799 0.5f : config.center_x/100.f;
800 float v = config.shape == GradientConfig::LINEAR ?
801 0.5f : config.center_y/100.f;
802 glUniform2f(glGetUniformLocation(shader, "center"),
804 glUniform1f(glGetUniformLocation(shader, "gradient_size"),
806 glUniform2f(glGetUniformLocation(shader, "angle"),
807 -sin(config.angle * (M_PI / 180)), cos(config.angle * (M_PI / 180)));
809 float in_radius = (float)config.in_radius/100;
810 float out_radius = (float)config.out_radius/100;
811 if( in_radius > out_radius ) {
813 in_radius = out_radius;
816 glUniform1f(glGetUniformLocation(shader, "in_radius"), in_radius);
817 glUniform1f(glGetUniformLocation(shader, "out_radius"), out_radius);
818 glUniform1f(glGetUniformLocation(shader, "radius_diff"),
819 out_radius - in_radius);
821 float in_r = (float)config.in_r / 0xff;
822 float in_g = (float)config.in_g / 0xff;
823 float in_b = (float)config.in_b / 0xff;
824 float in_a = (float)config.in_a / 0xff;
825 float out_r = (float)config.out_r / 0xff;
826 float out_g = (float)config.out_g / 0xff;
827 float out_b = (float)config.out_b / 0xff;
828 float out_a = (float)config.out_a / 0xff;
829 switch( get_output()->get_color_model() ) {
832 float in1, in2, in3, in4;
833 float out1, out2, out3, out4;
834 YUV::yuv.rgb_to_yuv_f(in_r,in_g,in_b, in1,in2,in3);
835 in2 += 0.5; in3 += 0.5; in4 = in_a;
836 YUV::yuv.rgb_to_yuv_f(out_r,out_g,out_b, out1,out2,out3);
837 out2 += 0.5; out3 += 0.5; out4 = out_a;
838 glUniform4f(glGetUniformLocation(shader, "out_color"),
839 out1, out2, out3, out4);
840 glUniform4f(glGetUniformLocation(shader, "in_color"),
845 glUniform4f(glGetUniformLocation(shader, "out_color"),
846 out_r, out_g, out_b, out_a);
847 glUniform4f(glGetUniformLocation(shader, "in_color"),
848 in_r, in_g, in_b, in_a);
853 get_output()->draw_texture();
855 get_output()->set_opengl_state(VFrame::SCREEN);
862 GradientPackage::GradientPackage()
867 GradientUnit::GradientUnit(GradientServer *server, GradientMain *plugin)
870 this->plugin = plugin;
871 this->server = server;
875 static float calculate_opacity(float mag,
876 float in_radius, float out_radius, int rate)
878 float mag_diff = mag - in_radius;
879 float radius_diff = out_radius - in_radius;
880 if( !radius_diff ) return 1.0;
883 case GradientConfig::LINEAR:
884 opacity = mag < in_radius ? 0.0 : mag >= out_radius ? 1.0 :
885 mag_diff / radius_diff;
887 case GradientConfig::LOG:
888 opacity = mag < in_radius ? 0.0 : // Let this one decay beyond out_radius
889 1 - exp(1.0 * -mag_diff / radius_diff);
891 case GradientConfig::SQUARE:
892 opacity = mag < in_radius ? 0.0 : mag >= out_radius ? 1.0 :
893 powf(mag_diff / radius_diff, 2.);
899 #define CREATE_GRADIENT(type, temp, components, max) { \
900 /* Synthesize linear gradient for lookups */ \
901 int grad_size = plugin->gradient_size; \
902 int n = sizeof(type) * (grad_size+1); \
903 void *r_table = (void*) (plugin->table + 0*n); \
904 void *g_table = (void*) (plugin->table + 1*n); \
905 void *b_table = (void*) (plugin->table + 2*n); \
906 void *a_table = (void*) (plugin->table + 3*n); \
907 double grad_size2 = grad_size / 2.; \
909 if( plugin->need_reconfigure ) { \
910 for( int i = 0; i <= grad_size; i++ ) { \
911 float opacity = calculate_opacity(i, in_radius, out_radius, plugin->config.rate); \
912 float transparency = 1.0 - opacity; \
913 ((type*)r_table)[i] = (type)(out1 * opacity + in1 * transparency); \
914 ((type*)g_table)[i] = (type)(out2 * opacity + in2 * transparency); \
915 ((type*)b_table)[i] = (type)(out3 * opacity + in3 * transparency); \
916 ((type*)a_table)[i] = (type)(out4 * opacity + in4 * transparency); \
920 for( int i = pkg->y1; i < pkg->y2; i++ ) { \
921 double y = half_h - i; \
922 type *gradient_row = (type*)plugin->gradient->get_rows()[i]; \
923 type *out_row = (type*)plugin->get_output()->get_rows()[i]; \
924 switch( plugin->config.shape ) { \
925 case GradientConfig::LINEAR: \
926 for( int j = 0; j < w; j++ ) { \
927 double x = j - half_w; \
928 /* Rotate by effect angle */ \
929 int mag = (grad_size2 - (x * sin_angle + y * cos_angle)) + 0.5; \
930 /* Get gradient value from these coords */ \
931 if( sizeof(type) == 4 ) { \
932 float opacity = calculate_opacity(mag, \
933 in_radius, out_radius, plugin->config.rate); \
934 float transparency = 1.0 - opacity; \
935 gradient_row[0] = (type)(out1 * opacity + in1 * transparency); \
936 gradient_row[1] = (type)(out2 * opacity + in2 * transparency); \
937 gradient_row[2] = (type)(out3 * opacity + in3 * transparency); \
938 if( components == 4 ) \
939 gradient_row[3] = (type)(out4 * opacity + in4 * transparency); \
941 else if( mag < 0 ) { \
942 gradient_row[0] = in1; \
943 gradient_row[1] = in2; \
944 gradient_row[2] = in3; \
945 if( components == 4 ) \
946 gradient_row[3] = in4; \
948 else if( mag >= grad_size ) { \
949 gradient_row[0] = out1; \
950 gradient_row[1] = out2; \
951 gradient_row[2] = out3; \
952 if( components == 4 ) \
953 gradient_row[3] = out4; \
956 gradient_row[0] = ((type*)r_table)[mag]; \
957 gradient_row[1] = ((type*)g_table)[mag]; \
958 gradient_row[2] = ((type*)b_table)[mag]; \
959 if( components == 4 ) \
960 gradient_row[3] = ((type*)a_table)[mag]; \
962 /* no alpha output, Overlay mixed colormodels */ \
963 if( gradient_cmodel != output_cmodel ) { \
964 temp opacity = gradient_row[3]; \
965 temp transparency = max - opacity; \
966 out_row[0] = (transparency * out_row[0] + opacity * gradient_row[0]) / max; \
967 out_row[1] = (transparency * out_row[1] + opacity * gradient_row[1]) / max; \
968 out_row[2] = (transparency * out_row[2] + opacity * gradient_row[2]) / max; \
971 gradient_row += components; \
975 case GradientConfig::RADIAL: \
976 for( int j = 0; j < w; j++ ) { \
977 double x = j - center_x, y = i - center_y; \
978 double magnitude = hypot(x, y); \
979 int mag = (int)magnitude; \
980 if( sizeof(type) == 4 ) { \
981 float opacity = calculate_opacity(mag, \
982 in_radius, out_radius, plugin->config.rate); \
983 float transparency = 1.0 - opacity; \
984 gradient_row[0] = (type)(out1 * opacity + in1 * transparency); \
985 gradient_row[1] = (type)(out2 * opacity + in2 * transparency); \
986 gradient_row[2] = (type)(out3 * opacity + in3 * transparency); \
987 if( components == 4 ) \
988 gradient_row[3] = (type)(out4 * opacity + in4 * transparency); \
991 gradient_row[0] = ((type*)r_table)[mag]; \
992 gradient_row[1] = ((type*)g_table)[mag]; \
993 gradient_row[2] = ((type*)b_table)[mag]; \
994 if( components == 4 ) \
995 gradient_row[3] = ((type*)a_table)[mag]; \
997 /* Overlay mixed colormodels onto output */ \
998 if( gradient_cmodel != output_cmodel ) { \
999 temp opacity = gradient_row[3]; \
1000 temp transparency = max - opacity; \
1001 out_row[0] = (transparency * out_row[0] + opacity * gradient_row[0]) / max; \
1002 out_row[1] = (transparency * out_row[1] + opacity * gradient_row[1]) / max; \
1003 out_row[2] = (transparency * out_row[2] + opacity * gradient_row[2]) / max; \
1006 gradient_row += components; \
1013 void GradientUnit::process_package(LoadPackage *package)
1015 GradientPackage *pkg = (GradientPackage*)package;
1016 int h = plugin->input->get_h();
1017 int w = plugin->input->get_w();
1018 int grad_size = plugin->gradient_size;
1021 int in_radius = (int)(plugin->config.in_radius / 100 * grad_size);
1022 int out_radius = (int)(plugin->config.out_radius / 100 * grad_size);
1023 double sin_angle = sin(plugin->config.angle * (M_PI / 180));
1024 double cos_angle = cos(plugin->config.angle * (M_PI / 180));
1025 double center_x = plugin->config.center_x * w / 100;
1026 double center_y = plugin->config.center_y * h / 100;
1027 int gradient_cmodel = plugin->gradient->get_color_model();
1028 int output_cmodel = plugin->get_output()->get_color_model();
1030 if( in_radius > out_radius ) {
1032 in_radius = out_radius;
1036 switch( gradient_cmodel ) {
1038 int in1 = plugin->config.in_r;
1039 int in2 = plugin->config.in_g;
1040 int in3 = plugin->config.in_b;
1041 int in4 = plugin->config.in_a;
1042 int out1 = plugin->config.out_r;
1043 int out2 = plugin->config.out_g;
1044 int out3 = plugin->config.out_b;
1045 int out4 = plugin->config.out_a;
1046 CREATE_GRADIENT(unsigned char, int, 3, 0xff)
1050 int in1 = plugin->config.in_r;
1051 int in2 = plugin->config.in_g;
1052 int in3 = plugin->config.in_b;
1053 int in4 = plugin->config.in_a;
1054 int out1 = plugin->config.out_r;
1055 int out2 = plugin->config.out_g;
1056 int out3 = plugin->config.out_b;
1057 int out4 = plugin->config.out_a;
1058 CREATE_GRADIENT(unsigned char, int, 4, 0xff)
1061 case BC_RGB_FLOAT: {
1062 float in1 = (float)plugin->config.in_r / 0xff;
1063 float in2 = (float)plugin->config.in_g / 0xff;
1064 float in3 = (float)plugin->config.in_b / 0xff;
1065 float in4 = (float)plugin->config.in_a / 0xff;
1066 float out1 = (float)plugin->config.out_r / 0xff;
1067 float out2 = (float)plugin->config.out_g / 0xff;
1068 float out3 = (float)plugin->config.out_b / 0xff;
1069 float out4 = (float)plugin->config.out_a / 0xff;
1070 CREATE_GRADIENT(float, float, 3, 1.0)
1073 case BC_RGBA_FLOAT: {
1074 float in1 = (float)plugin->config.in_r / 0xff;
1075 float in2 = (float)plugin->config.in_g / 0xff;
1076 float in3 = (float)plugin->config.in_b / 0xff;
1077 float in4 = (float)plugin->config.in_a / 0xff;
1078 float out1 = (float)plugin->config.out_r / 0xff;
1079 float out2 = (float)plugin->config.out_g / 0xff;
1080 float out3 = (float)plugin->config.out_b / 0xff;
1081 float out4 = (float)plugin->config.out_a / 0xff;
1082 CREATE_GRADIENT(float, float, 4, 1.0)
1086 int in_r = plugin->config.in_r;
1087 int in_g = plugin->config.in_g;
1088 int in_b = plugin->config.in_b;
1089 int in1, in2, in3, in4;
1090 int out1, out2, out3, out4;
1091 YUV::yuv.rgb_to_yuv_8(in_r,in_g,in_b, in1,in2,in3);
1092 in4 = plugin->config.in_a;
1093 int out_r = plugin->config.in_r;
1094 int out_g = plugin->config.in_g;
1095 int out_b = plugin->config.in_b;
1096 YUV::yuv.rgb_to_yuv_8(out_r,out_g,out_b, out1,out2,out3);
1097 out4 = plugin->config.out_a;
1098 CREATE_GRADIENT(unsigned char, int, 3, 0xff)
1102 int in_r = plugin->config.in_r;
1103 int in_g = plugin->config.in_g;
1104 int in_b = plugin->config.in_b;
1105 int in1, in2, in3, in4;
1106 int out1, out2, out3, out4;
1107 YUV::yuv.rgb_to_yuv_8(in_r,in_g,in_b, in1,in2,in3);
1108 in4 = plugin->config.in_a;
1109 int out_r = plugin->config.in_r;
1110 int out_g = plugin->config.in_g;
1111 int out_b = plugin->config.in_b;
1112 YUV::yuv.rgb_to_yuv_8(out_r,out_g,out_b, out1,out2,out3);
1113 out4 = plugin->config.out_a;
1114 CREATE_GRADIENT(unsigned char, int, 4, 0xff)
1120 GradientServer::GradientServer(GradientMain *plugin,
1121 int total_clients, int total_packages)
1122 : LoadServer(total_clients, total_packages)
1124 this->plugin = plugin;
1127 void GradientServer::init_packages()
1129 for( int i = 0; i < get_total_packages(); i++ ) {
1130 GradientPackage *package = (GradientPackage*)get_package(i);
1131 package->y1 = plugin->input->get_h() *
1133 get_total_packages();
1134 package->y2 = plugin->input->get_h() *
1136 get_total_packages();
1140 LoadClient* GradientServer::new_client()
1142 return new GradientUnit(this, plugin);
1145 LoadPackage* GradientServer::new_package()
1147 return new GradientPackage;