00001 #include <math.h>
00002 #include <stdint.h>
00003 #include <string.h>
00004
00005 #include "bcdisplayinfo.h"
00006 #include "clip.h"
00007 #include "bchash.h"
00008 #include "filexml.h"
00009 #include "gradient.h"
00010 #include "keyframe.h"
00011 #include "language.h"
00012 #include "overlayframe.h"
00013 #include "picon_png.h"
00014 #include "vframe.h"
00015
00016
00017
00018
00019 REGISTER_PLUGIN(GradientMain)
00020
00021
00022
00023
00024
00025
00026 GradientConfig::GradientConfig()
00027 {
00028 angle = 0;
00029 in_radius = 0;
00030 out_radius = 100;
00031 in_r = 0xff;
00032 in_g = 0xff;
00033 in_b = 0xff;
00034 in_a = 0xff;
00035 out_r = 0x0;
00036 out_g = 0x0;
00037 out_b = 0x0;
00038 out_a = 0x0;
00039 shape = GradientConfig::LINEAR;
00040 rate = GradientConfig::LINEAR;
00041 center_x = 50;
00042 center_y = 50;
00043 }
00044
00045 int GradientConfig::equivalent(GradientConfig &that)
00046 {
00047 return (EQUIV(angle, that.angle) &&
00048 EQUIV(in_radius, that.in_radius) &&
00049 EQUIV(out_radius, that.out_radius) &&
00050 in_r == that.in_r &&
00051 in_g == that.in_g &&
00052 in_b == that.in_b &&
00053 in_a == that.in_a &&
00054 out_r == that.out_r &&
00055 out_g == that.out_g &&
00056 out_b == that.out_b &&
00057 out_a == that.out_a &&
00058 shape == that.shape &&
00059 rate == that.rate &&
00060 EQUIV(center_x, that.center_x) &&
00061 EQUIV(center_y, that.center_y));
00062 }
00063
00064 void GradientConfig::copy_from(GradientConfig &that)
00065 {
00066 angle = that.angle;
00067 in_radius = that.in_radius;
00068 out_radius = that.out_radius;
00069 in_r = that.in_r;
00070 in_g = that.in_g;
00071 in_b = that.in_b;
00072 in_a = that.in_a;
00073 out_r = that.out_r;
00074 out_g = that.out_g;
00075 out_b = that.out_b;
00076 out_a = that.out_a;
00077 shape = that.shape;
00078 rate = that.rate;
00079 center_x = that.center_x;
00080 center_y = that.center_y;
00081 }
00082
00083 void GradientConfig::interpolate(GradientConfig &prev,
00084 GradientConfig &next,
00085 long prev_frame,
00086 long next_frame,
00087 long current_frame)
00088 {
00089 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
00090 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
00091
00092
00093 this->angle = (int)(prev.angle * prev_scale + next.angle * next_scale);
00094 this->in_radius = (int)(prev.in_radius * prev_scale + next.in_radius * next_scale);
00095 this->out_radius = (int)(prev.out_radius * prev_scale + next.out_radius * next_scale);
00096 in_r = (int)(prev.in_r * prev_scale + next.in_r * next_scale);
00097 in_g = (int)(prev.in_g * prev_scale + next.in_g * next_scale);
00098 in_b = (int)(prev.in_b * prev_scale + next.in_b * next_scale);
00099 in_a = (int)(prev.in_a * prev_scale + next.in_a * next_scale);
00100 out_r = (int)(prev.out_r * prev_scale + next.out_r * next_scale);
00101 out_g = (int)(prev.out_g * prev_scale + next.out_g * next_scale);
00102 out_b = (int)(prev.out_b * prev_scale + next.out_b * next_scale);
00103 out_a = (int)(prev.out_a * prev_scale + next.out_a * next_scale);
00104 shape = prev.shape;
00105 rate = prev.rate;
00106 center_x = prev.center_x * prev_scale + next.center_x * next_scale;
00107 center_y = prev.center_y * prev_scale + next.center_y * next_scale;
00108 }
00109
00110 int GradientConfig::get_in_color()
00111 {
00112 int result = (in_r << 16) | (in_g << 8) | (in_b);
00113 return result;
00114 }
00115
00116 int GradientConfig::get_out_color()
00117 {
00118 int result = (out_r << 16) | (out_g << 8) | (out_b);
00119 return result;
00120 }
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130 PLUGIN_THREAD_OBJECT(GradientMain, GradientThread, GradientWindow)
00131
00132
00133 #define COLOR_W 100
00134 #define COLOR_H 30
00135
00136 GradientWindow::GradientWindow(GradientMain *plugin, int x, int y)
00137 : BC_Window(plugin->gui_string,
00138 x,
00139 y,
00140 350,
00141 290,
00142 350,
00143 290,
00144 0,
00145 1)
00146 {
00147 this->plugin = plugin;
00148 angle = 0;
00149 angle_title = 0;
00150 center_x = 0;
00151 center_y = 0;
00152 center_x_title = 0;
00153 center_y_title = 0;
00154 }
00155
00156 GradientWindow::~GradientWindow()
00157 {
00158 delete in_color_thread;
00159 delete out_color_thread;
00160 }
00161
00162 int GradientWindow::create_objects()
00163 {
00164 int x = 10, y = 10;
00165 BC_Title *title;
00166
00167 add_subwindow(title = new BC_Title(x, y, _("Shape:")));
00168 add_subwindow(shape = new GradientShape(plugin,
00169 this,
00170 x + title->get_w() + 10,
00171 y));
00172 shape->create_objects();
00173 y += 40;
00174 shape_x = x;
00175 shape_y = y;
00176 y += 40;
00177 add_subwindow(title = new BC_Title(x, y, _("Rate:")));
00178 add_subwindow(rate = new GradientRate(plugin,
00179 x + title->get_w() + 10,
00180 y));
00181 rate->create_objects();
00182 y += 40;
00183 add_subwindow(title = new BC_Title(x, y, _("Inner radius:")));
00184 add_subwindow(in_radius = new GradientInRadius(plugin, x + title->get_w() + 10, y));
00185 y += 30;
00186 add_subwindow(title = new BC_Title(x, y, _("Outer radius:")));
00187 add_subwindow(out_radius = new GradientOutRadius(plugin, x + title->get_w() + 10, y));
00188 y += 35;
00189 add_subwindow(in_color = new GradientInColorButton(plugin, this, x, y));
00190 in_color_x = x + in_color->get_w() + 10;
00191 in_color_y = y;
00192 y += 35;
00193 add_subwindow(out_color = new GradientOutColorButton(plugin, this, x, y));
00194 out_color_x = x + out_color->get_w() + 10;
00195 out_color_y = y;
00196 in_color_thread = new GradientInColorThread(plugin, this);
00197 out_color_thread = new GradientOutColorThread(plugin, this);
00198 update_in_color();
00199 update_out_color();
00200 update_shape();
00201
00202 show_window();
00203 flush();
00204 return 0;
00205 }
00206
00207 void GradientWindow::update_shape()
00208 {
00209 int x = shape_x, y = shape_y;
00210
00211 if(plugin->config.shape == GradientConfig::LINEAR)
00212 {
00213 delete center_x_title;
00214 delete center_y_title;
00215 delete center_x;
00216 delete center_y;
00217 center_x_title = 0;
00218 center_y_title = 0;
00219 center_x = 0;
00220 center_y = 0;
00221
00222 if(!angle)
00223 {
00224 add_subwindow(angle_title = new BC_Title(x, y, _("Angle:")));
00225 add_subwindow(angle = new GradientAngle(plugin, x + angle_title->get_w() + 10, y));
00226 }
00227 }
00228 else
00229 {
00230 delete angle_title;
00231 delete angle;
00232 angle_title = 0;
00233 angle = 0;
00234 if(!center_x)
00235 {
00236 add_subwindow(center_x_title = new BC_Title(x, y, _("Center X:")));
00237 add_subwindow(center_x = new GradientCenterX(plugin,
00238 x + center_x_title->get_w() + 10,
00239 y));
00240 x += center_x_title->get_w() + 10 + center_x->get_w() + 10;
00241 add_subwindow(center_y_title = new BC_Title(x, y, _("Center Y:")));
00242 add_subwindow(center_y = new GradientCenterY(plugin,
00243 x + center_y_title->get_w() + 10,
00244 y));
00245 }
00246 }
00247 }
00248
00249 int GradientWindow::close_event()
00250 {
00251
00252 set_done(1);
00253 return 1;
00254 }
00255
00256 void GradientWindow::update_in_color()
00257 {
00258
00259 set_color(plugin->config.get_in_color());
00260 draw_box(in_color_x, in_color_y, COLOR_W, COLOR_H);
00261 flash(in_color_x, in_color_y, COLOR_W, COLOR_H);
00262 }
00263
00264 void GradientWindow::update_out_color()
00265 {
00266
00267 set_color(plugin->config.get_out_color());
00268 draw_box(out_color_x, out_color_y, COLOR_W, COLOR_H);
00269 flash(out_color_x, out_color_y, COLOR_W, COLOR_H);
00270 }
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280 GradientShape::GradientShape(GradientMain *plugin,
00281 GradientWindow *gui,
00282 int x,
00283 int y)
00284 : BC_PopupMenu(x, y, 100, to_text(plugin->config.shape), 1)
00285 {
00286 this->plugin = plugin;
00287 this->gui = gui;
00288 }
00289 void GradientShape::create_objects()
00290 {
00291 add_item(new BC_MenuItem(to_text(GradientConfig::LINEAR)));
00292 add_item(new BC_MenuItem(to_text(GradientConfig::RADIAL)));
00293 }
00294 char* GradientShape::to_text(int shape)
00295 {
00296 switch(shape)
00297 {
00298 case GradientConfig::LINEAR:
00299 return _("Linear");
00300 default:
00301 return _("Radial");
00302 }
00303 }
00304 int GradientShape::from_text(char *text)
00305 {
00306 if(!strcmp(text, to_text(GradientConfig::LINEAR)))
00307 return GradientConfig::LINEAR;
00308 return GradientConfig::RADIAL;
00309 }
00310 int GradientShape::handle_event()
00311 {
00312 plugin->config.shape = from_text(get_text());
00313 gui->update_shape();
00314 plugin->send_configure_change();
00315 }
00316
00317
00318
00319
00320 GradientCenterX::GradientCenterX(GradientMain *plugin, int x, int y)
00321 : BC_FPot(x, y, plugin->config.center_x, 0, 100)
00322 {
00323 this->plugin = plugin;
00324 }
00325 int GradientCenterX::handle_event()
00326 {
00327 plugin->config.center_x = get_value();
00328 plugin->send_configure_change();
00329 return 1;
00330 }
00331
00332
00333
00334 GradientCenterY::GradientCenterY(GradientMain *plugin, int x, int y)
00335 : BC_FPot(x, y, plugin->config.center_y, 0, 100)
00336 {
00337 this->plugin = plugin;
00338 }
00339
00340 int GradientCenterY::handle_event()
00341 {
00342 plugin->config.center_y = get_value();
00343 plugin->send_configure_change();
00344 return 1;
00345 }
00346
00347
00348
00349
00350 GradientAngle::GradientAngle(GradientMain *plugin, int x, int y)
00351 : BC_FPot(x,
00352 y,
00353 plugin->config.angle,
00354 -180,
00355 180)
00356 {
00357 this->plugin = plugin;
00358 }
00359
00360 int GradientAngle::handle_event()
00361 {
00362 plugin->config.angle = get_value();
00363 plugin->send_configure_change();
00364 return 1;
00365 }
00366
00367
00368 GradientRate::GradientRate(GradientMain *plugin, int x, int y)
00369 : BC_PopupMenu(x,
00370 y,
00371 100,
00372 to_text(plugin->config.rate),
00373 1)
00374 {
00375 this->plugin = plugin;
00376 }
00377 void GradientRate::create_objects()
00378 {
00379 add_item(new BC_MenuItem(to_text(GradientConfig::LINEAR)));
00380 add_item(new BC_MenuItem(to_text(GradientConfig::LOG)));
00381 add_item(new BC_MenuItem(to_text(GradientConfig::SQUARE)));
00382 }
00383 char* GradientRate::to_text(int shape)
00384 {
00385 switch(shape)
00386 {
00387 case GradientConfig::LINEAR:
00388 return _("Linear");
00389 case GradientConfig::LOG:
00390 return _("Log");
00391 default:
00392 return _("Square");
00393 }
00394 }
00395 int GradientRate::from_text(char *text)
00396 {
00397 if(!strcmp(text, to_text(GradientConfig::LINEAR)))
00398 return GradientConfig::LINEAR;
00399 if(!strcmp(text, to_text(GradientConfig::LOG)))
00400 return GradientConfig::LOG;
00401 return GradientConfig::SQUARE;
00402 }
00403 int GradientRate::handle_event()
00404 {
00405 plugin->config.rate = from_text(get_text());
00406 plugin->send_configure_change();
00407 return 1;
00408 }
00409
00410
00411
00412 GradientInRadius::GradientInRadius(GradientMain *plugin, int x, int y)
00413 : BC_FSlider(x,
00414 y,
00415 0,
00416 200,
00417 200,
00418 (float)0,
00419 (float)100,
00420 (float)plugin->config.in_radius)
00421 {
00422 this->plugin = plugin;
00423 }
00424
00425 int GradientInRadius::handle_event()
00426 {
00427 plugin->config.in_radius = get_value();
00428 plugin->send_configure_change();
00429 return 1;
00430 }
00431
00432
00433 GradientOutRadius::GradientOutRadius(GradientMain *plugin, int x, int y)
00434 : BC_FSlider(x,
00435 y,
00436 0,
00437 200,
00438 200,
00439 (float)0,
00440 (float)100,
00441 (float)plugin->config.out_radius)
00442 {
00443 this->plugin = plugin;
00444 }
00445
00446 int GradientOutRadius::handle_event()
00447 {
00448 plugin->config.out_radius = get_value();
00449 plugin->send_configure_change();
00450 return 1;
00451 }
00452
00453 GradientInColorButton::GradientInColorButton(GradientMain *plugin, GradientWindow *window, int x, int y)
00454 : BC_GenericButton(x, y, _("Inner color:"))
00455 {
00456 this->plugin = plugin;
00457 this->window = window;
00458 }
00459
00460 int GradientInColorButton::handle_event()
00461 {
00462 window->in_color_thread->start_window(
00463 plugin->config.get_in_color(),
00464 plugin->config.in_a);
00465 return 1;
00466 }
00467
00468
00469 GradientOutColorButton::GradientOutColorButton(GradientMain *plugin, GradientWindow *window, int x, int y)
00470 : BC_GenericButton(x, y, _("Outer color:"))
00471 {
00472 this->plugin = plugin;
00473 this->window = window;
00474 }
00475
00476 int GradientOutColorButton::handle_event()
00477 {
00478 window->out_color_thread->start_window(
00479 plugin->config.get_out_color(),
00480 plugin->config.out_a);
00481 return 1;
00482 }
00483
00484
00485
00486 GradientInColorThread::GradientInColorThread(GradientMain *plugin,
00487 GradientWindow *window)
00488 : ColorThread(1, _("Inner color"))
00489 {
00490 this->plugin = plugin;
00491 this->window = window;
00492 }
00493
00494 int GradientInColorThread::handle_new_color(int output, int alpha)
00495 {
00496 plugin->config.in_r = (output & 0xff0000) >> 16;
00497 plugin->config.in_g = (output & 0xff00) >> 8;
00498 plugin->config.in_b = (output & 0xff);
00499 plugin->config.in_a = alpha;
00500 window->update_in_color();
00501 window->flush();
00502 plugin->send_configure_change();
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513 return 1;
00514 }
00515
00516
00517
00518 GradientOutColorThread::GradientOutColorThread(GradientMain *plugin,
00519 GradientWindow *window)
00520 : ColorThread(1, _("Outer color"))
00521 {
00522 this->plugin = plugin;
00523 this->window = window;
00524 }
00525
00526 int GradientOutColorThread::handle_new_color(int output, int alpha)
00527 {
00528 plugin->config.out_r = (output & 0xff0000) >> 16;
00529 plugin->config.out_g = (output & 0xff00) >> 8;
00530 plugin->config.out_b = (output & 0xff);
00531 plugin->config.out_a = alpha;
00532 window->update_out_color();
00533 window->flush();
00534 plugin->send_configure_change();
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544 return 1;
00545 }
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558 GradientMain::GradientMain(PluginServer *server)
00559 : PluginVClient(server)
00560 {
00561 PLUGIN_CONSTRUCTOR_MACRO
00562 need_reconfigure = 1;
00563 gradient = 0;
00564 engine = 0;
00565 overlayer = 0;
00566 }
00567
00568 GradientMain::~GradientMain()
00569 {
00570 PLUGIN_DESTRUCTOR_MACRO
00571
00572 if(gradient) delete gradient;
00573 if(engine) delete engine;
00574 if(overlayer) delete overlayer;
00575 }
00576
00577 char* GradientMain::plugin_title() { return N_("Gradient"); }
00578 int GradientMain::is_realtime() { return 1; }
00579
00580
00581 NEW_PICON_MACRO(GradientMain)
00582
00583 SHOW_GUI_MACRO(GradientMain, GradientThread)
00584
00585 SET_STRING_MACRO(GradientMain)
00586
00587 RAISE_WINDOW_MACRO(GradientMain)
00588
00589 LOAD_CONFIGURATION_MACRO(GradientMain, GradientConfig)
00590
00591 int GradientMain::is_synthesis()
00592 {
00593 return 1;
00594 }
00595
00596
00597 int GradientMain::process_buffer(VFrame *frame,
00598 int64_t start_position,
00599 double frame_rate)
00600 {
00601 this->input = frame;
00602 this->output = frame;
00603 need_reconfigure |= load_configuration();
00604
00605 int need_alpha = config.in_a != 0xff || config.out_a != 0xff;
00606 if(need_alpha)
00607 read_frame(frame,
00608 0,
00609 start_position,
00610 frame_rate,
00611 get_use_opengl());
00612 if(get_use_opengl()) return run_opengl();
00613
00614 int gradient_cmodel = input->get_color_model();
00615 if(need_alpha && cmodel_components(gradient_cmodel) == 3)
00616 {
00617 switch(gradient_cmodel)
00618 {
00619 case BC_RGB888:
00620 gradient_cmodel = BC_RGBA8888;
00621 break;
00622 case BC_RGB_FLOAT:
00623 gradient_cmodel = BC_RGBA_FLOAT;
00624 break;
00625 case BC_YUV888:
00626 gradient_cmodel = BC_YUVA8888;
00627 break;
00628 }
00629 }
00630
00631 if(gradient && gradient->get_color_model() != gradient_cmodel)
00632 {
00633 delete gradient;
00634 gradient = 0;
00635 }
00636
00637 if(!gradient) gradient = new VFrame(0,
00638 input->get_w(),
00639 input->get_h(),
00640 gradient_cmodel);
00641
00642 if(!engine) engine = new GradientServer(this,
00643 get_project_smp() + 1,
00644 get_project_smp() + 1);
00645 engine->process_packages();
00646
00647
00648 if(gradient->get_color_model() == output->get_color_model())
00649 {
00650 if(!overlayer) overlayer = new OverlayFrame(get_project_smp() + 1);
00651 overlayer->overlay(output,
00652 gradient,
00653 0,
00654 0,
00655 input->get_w(),
00656 input->get_h(),
00657 0,
00658 0,
00659 input->get_w(),
00660 input->get_h(),
00661 1.0,
00662 TRANSFER_NORMAL,
00663 NEAREST_NEIGHBOR);
00664 }
00665
00666
00667 return 0;
00668 }
00669
00670
00671 void GradientMain::update_gui()
00672 {
00673 if(thread)
00674 {
00675 if(load_configuration())
00676 {
00677 thread->window->lock_window("GradientMain::update_gui");
00678 thread->window->rate->set_text(GradientRate::to_text(config.rate));
00679 thread->window->in_radius->update(config.in_radius);
00680 thread->window->out_radius->update(config.out_radius);
00681 thread->window->shape->set_text(GradientShape::to_text(config.shape));
00682 if(thread->window->angle)
00683 thread->window->angle->update(config.angle);
00684 if(thread->window->center_x)
00685 thread->window->center_x->update(config.center_x);
00686 if(thread->window->center_y)
00687 thread->window->center_y->update(config.center_y);
00688 thread->window->update_in_color();
00689 thread->window->update_out_color();
00690 thread->window->update_shape();
00691 thread->window->unlock_window();
00692 thread->window->in_color_thread->update_gui(config.get_in_color(), config.in_a);
00693 thread->window->out_color_thread->update_gui(config.get_out_color(), config.out_a);
00694 }
00695 }
00696 }
00697
00698
00699 int GradientMain::load_defaults()
00700 {
00701 char directory[1024], string[1024];
00702
00703 sprintf(directory, "%sgradient.rc", BCASTDIR);
00704
00705
00706 defaults = new BC_Hash(directory);
00707 defaults->load();
00708
00709
00710
00711
00712
00713
00714 config.angle = defaults->get("ANGLE", config.angle);
00715 config.in_radius = defaults->get("IN_RADIUS", config.in_radius);
00716 config.out_radius = defaults->get("OUT_RADIUS", config.out_radius);
00717 config.in_r = defaults->get("IN_R", config.in_r);
00718 config.in_g = defaults->get("IN_G", config.in_g);
00719 config.in_b = defaults->get("IN_B", config.in_b);
00720 config.in_a = defaults->get("IN_A", config.in_a);
00721 config.out_r = defaults->get("OUT_R", config.out_r);
00722 config.out_g = defaults->get("OUT_G", config.out_g);
00723 config.out_b = defaults->get("OUT_B", config.out_b);
00724 config.out_a = defaults->get("OUT_A", config.out_a);
00725 config.shape = defaults->get("SHAPE", config.shape);
00726 config.rate = defaults->get("RATE", config.rate);
00727 config.center_x = defaults->get("CENTER_X", config.center_x);
00728 config.center_y = defaults->get("CENTER_Y", config.center_y);
00729 return 0;
00730 }
00731
00732
00733 int GradientMain::save_defaults()
00734 {
00735 defaults->update("ANGLE", config.angle);
00736 defaults->update("IN_RADIUS", config.in_radius);
00737 defaults->update("OUT_RADIUS", config.out_radius);
00738 defaults->update("IN_R", config.in_r);
00739 defaults->update("IN_G", config.in_g);
00740 defaults->update("IN_B", config.in_b);
00741 defaults->update("IN_A", config.in_a);
00742 defaults->update("OUT_R", config.out_r);
00743 defaults->update("OUT_G", config.out_g);
00744 defaults->update("OUT_B", config.out_b);
00745 defaults->update("OUT_A", config.out_a);
00746 defaults->update("RATE", config.rate);
00747 defaults->update("SHAPE", config.shape);
00748 defaults->update("CENTER_X", config.center_x);
00749 defaults->update("CENTER_Y", config.center_y);
00750 defaults->save();
00751 return 0;
00752 }
00753
00754
00755
00756 void GradientMain::save_data(KeyFrame *keyframe)
00757 {
00758 FileXML output;
00759
00760
00761 output.set_shared_string(keyframe->data, MESSAGESIZE);
00762 output.tag.set_title("GRADIENT");
00763
00764 output.tag.set_property("ANGLE", config.angle);
00765 output.tag.set_property("IN_RADIUS", config.in_radius);
00766 output.tag.set_property("OUT_RADIUS", config.out_radius);
00767 output.tag.set_property("IN_R", config.in_r);
00768 output.tag.set_property("IN_G", config.in_g);
00769 output.tag.set_property("IN_B", config.in_b);
00770 output.tag.set_property("IN_A", config.in_a);
00771 output.tag.set_property("OUT_R", config.out_r);
00772 output.tag.set_property("OUT_G", config.out_g);
00773 output.tag.set_property("OUT_B", config.out_b);
00774 output.tag.set_property("OUT_A", config.out_a);
00775 output.tag.set_property("SHAPE", config.shape);
00776 output.tag.set_property("RATE", config.rate);
00777 output.tag.set_property("CENTER_X", config.center_x);
00778 output.tag.set_property("CENTER_Y", config.center_y);
00779 output.append_tag();
00780 output.tag.set_title("/GRADIENT");
00781 output.append_tag();
00782 output.terminate_string();
00783 }
00784
00785 void GradientMain::read_data(KeyFrame *keyframe)
00786 {
00787 FileXML input;
00788
00789 input.set_shared_string(keyframe->data, strlen(keyframe->data));
00790
00791 int result = 0;
00792
00793 while(!result)
00794 {
00795 result = input.read_tag();
00796
00797 if(!result)
00798 {
00799 if(input.tag.title_is("GRADIENT"))
00800 {
00801 config.angle = input.tag.get_property("ANGLE", config.angle);
00802 config.rate = input.tag.get_property("RATE", config.rate);
00803 config.in_radius = input.tag.get_property("IN_RADIUS", config.in_radius);
00804 config.out_radius = input.tag.get_property("OUT_RADIUS", config.out_radius);
00805 config.in_r = input.tag.get_property("IN_R", config.in_r);
00806 config.in_g = input.tag.get_property("IN_G", config.in_g);
00807 config.in_b = input.tag.get_property("IN_B", config.in_b);
00808 config.in_a = input.tag.get_property("IN_A", config.in_a);
00809 config.out_r = input.tag.get_property("OUT_R", config.out_r);
00810 config.out_g = input.tag.get_property("OUT_G", config.out_g);
00811 config.out_b = input.tag.get_property("OUT_B", config.out_b);
00812 config.out_a = input.tag.get_property("OUT_A", config.out_a);
00813 config.shape = input.tag.get_property("SHAPE", config.shape);
00814 config.center_x = input.tag.get_property("CENTER_X", config.center_x);
00815 config.center_y = input.tag.get_property("CENTER_Y", config.center_y);
00816 }
00817 }
00818 }
00819 }
00820
00821 int GradientMain::handle_opengl()
00822 {
00823 #ifdef HAVE_GL
00824 char *head_frag =
00825 "uniform sampler2D tex;\n"
00826 "uniform float half_w;\n"
00827 "uniform float half_h;\n"
00828 "uniform float center_x;\n"
00829 "uniform float center_y;\n"
00830 "uniform float half_gradient_size;\n"
00831 "uniform float sin_angle;\n"
00832 "uniform float cos_angle;\n"
00833 "uniform vec4 out_color;\n"
00834 "uniform vec4 in_color;\n"
00835 "uniform float in_radius;\n"
00836 "uniform float out_radius;\n"
00837 "uniform float radius_diff;\n"
00838 "\n"
00839 "void main()\n"
00840 "{\n"
00841 " vec2 out_coord = gl_TexCoord[0].st;\n";
00842
00843 char *linear_shape =
00844 " vec2 in_coord = vec2(out_coord.x - half_w, half_h - out_coord.y);\n"
00845 " float mag = half_gradient_size - \n"
00846 " (in_coord.x * sin_angle + in_coord.y * cos_angle);\n";
00847
00848 char *radial_shape =
00849 " vec2 in_coord = vec2(out_coord.x - center_x, out_coord.y - center_y);\n"
00850 " float mag = length(vec2(in_coord.x, in_coord.y));\n";
00851
00852
00853 char *linear_rate =
00854 " mag = min(max(mag, in_radius), out_radius);\n"
00855 " float opacity = (mag - in_radius) / radius_diff;\n";
00856
00857
00858 char *log_rate =
00859 " mag = max(mag, in_radius);\n"
00860 " float opacity = 1.0 - \n"
00861 " exp(1.0 * -(mag - in_radius) / radius_diff);\n";
00862
00863 char *square_rate =
00864 " mag = min(max(mag, in_radius), out_radius);\n"
00865 " float opacity = pow((mag - in_radius) / radius_diff, 2.0);\n"
00866 " opacity = min(opacity, 1.0);\n";
00867
00868 char *tail_frag =
00869 " vec4 color = mix(in_color, out_color, opacity);\n"
00870 " vec4 bg_color = texture2D(tex, out_coord);\n"
00871 " gl_FragColor.rgb = mix(bg_color.rgb, color.rgb, color.a);\n"
00872 " gl_FragColor.a = max(bg_color.a, color.a);\n"
00873 "}\n";
00874
00875
00876 char *shader_stack[5] = { 0, 0, 0, 0, 0 };
00877 shader_stack[0] = head_frag;
00878
00879 switch(config.shape)
00880 {
00881 case GradientConfig::LINEAR:
00882 shader_stack[1] = linear_shape;
00883 break;
00884
00885 default:
00886 shader_stack[1] = radial_shape;
00887 break;
00888 }
00889
00890 switch(config.rate)
00891 {
00892 case GradientConfig::LINEAR:
00893 shader_stack[2] = linear_rate;
00894 break;
00895 case GradientConfig::LOG:
00896 shader_stack[2] = log_rate;
00897 break;
00898 case GradientConfig::SQUARE:
00899 shader_stack[2] = square_rate;
00900 break;
00901 }
00902
00903 shader_stack[3] = tail_frag;
00904
00905 if(config.in_a >= 0xff &&
00906 config.out_a >= 0xff)
00907 get_output()->set_opengl_state(VFrame::TEXTURE);
00908 get_output()->to_texture();
00909 get_output()->enable_opengl();
00910 get_output()->init_screen();
00911 get_output()->bind_texture(0);
00912
00913 unsigned int frag = VFrame::make_shader(0,
00914 shader_stack[0],
00915 shader_stack[1],
00916 shader_stack[2],
00917 shader_stack[3],
00918 0);
00919
00920 if(frag)
00921 {
00922 glUseProgram(frag);
00923 float w = get_output()->get_w();
00924 float h = get_output()->get_h();
00925 float texture_w = get_output()->get_texture_w();
00926 float texture_h = get_output()->get_texture_h();
00927 glUniform1i(glGetUniformLocation(frag, "tex"), 0);
00928 glUniform1f(glGetUniformLocation(frag, "half_w"), w / 2 / texture_w);
00929 glUniform1f(glGetUniformLocation(frag, "half_h"), h / 2 / texture_h);
00930 if(config.shape == GradientConfig::LINEAR)
00931 {
00932 glUniform1f(glGetUniformLocation(frag, "center_x"),
00933 w / 2 / texture_w);
00934 glUniform1f(glGetUniformLocation(frag, "center_y"),
00935 h / 2 / texture_h);
00936 }
00937 else
00938 {
00939 glUniform1f(glGetUniformLocation(frag, "center_x"),
00940 (float)config.center_x * w / 100 / texture_w);
00941 glUniform1f(glGetUniformLocation(frag, "center_y"),
00942 (float)config.center_y * h / 100 / texture_h);
00943 }
00944 float gradient_size = hypotf(w / texture_w, h / texture_h);
00945 glUniform1f(glGetUniformLocation(frag, "half_gradient_size"),
00946 gradient_size / 2);
00947 glUniform1f(glGetUniformLocation(frag, "sin_angle"),
00948 sin(config.angle * (M_PI / 180)));
00949 glUniform1f(glGetUniformLocation(frag, "cos_angle"),
00950 cos(config.angle * (M_PI / 180)));
00951 float in_radius = (float)config.in_radius / 100 * gradient_size;
00952 glUniform1f(glGetUniformLocation(frag, "in_radius"), in_radius);
00953 float out_radius = (float)config.out_radius / 100 * gradient_size;
00954 glUniform1f(glGetUniformLocation(frag, "out_radius"), out_radius);
00955 glUniform1f(glGetUniformLocation(frag, "radius_diff"),
00956 out_radius - in_radius);
00957
00958 switch(get_output()->get_color_model())
00959 {
00960 case BC_YUV888:
00961 case BC_YUVA8888:
00962 {
00963 float in1, in2, in3, in4;
00964 float out1, out2, out3, out4;
00965 YUV::rgb_to_yuv_f((float)config.in_r / 0xff,
00966 (float)config.in_g / 0xff,
00967 (float)config.in_b / 0xff,
00968 in1,
00969 in2,
00970 in3);
00971 in4 = (float)config.in_a / 0xff;
00972 YUV::rgb_to_yuv_f((float)config.out_r / 0xff,
00973 (float)config.out_g / 0xff,
00974 (float)config.out_b / 0xff,
00975 out1,
00976 out2,
00977 out3);
00978 in2 += 0.5;
00979 in3 += 0.5;
00980 out2 += 0.5;
00981 out3 += 0.5;
00982 out4 = (float)config.out_a / 0xff;
00983 glUniform4f(glGetUniformLocation(frag, "out_color"),
00984 out1, out2, out3, out4);
00985 glUniform4f(glGetUniformLocation(frag, "in_color"),
00986 in1, in2, in3, in4);
00987 break;
00988 }
00989
00990 default:
00991 glUniform4f(glGetUniformLocation(frag, "out_color"),
00992 (float)config.out_r / 0xff,
00993 (float)config.out_g / 0xff,
00994 (float)config.out_b / 0xff,
00995 (float)config.out_a / 0xff);
00996 glUniform4f(glGetUniformLocation(frag, "in_color"),
00997 (float)config.in_r / 0xff,
00998 (float)config.in_g / 0xff,
00999 (float)config.in_b / 0xff,
01000 (float)config.in_a / 0xff);
01001 break;
01002 }
01003 }
01004
01005 get_output()->draw_texture();
01006 glUseProgram(0);
01007 get_output()->set_opengl_state(VFrame::SCREEN);
01008
01009 #endif
01010 }
01011
01012
01013
01014
01015
01016
01017
01018
01019
01020
01021
01022 GradientPackage::GradientPackage()
01023 : LoadPackage()
01024 {
01025 }
01026
01027
01028
01029
01030 GradientUnit::GradientUnit(GradientServer *server, GradientMain *plugin)
01031 : LoadClient(server)
01032 {
01033 this->plugin = plugin;
01034 this->server = server;
01035 }
01036
01037
01038 #define SQR(x) ((x) * (x))
01039
01040
01041 static float calculate_opacity(float mag,
01042 float in_radius,
01043 float out_radius,
01044 int rate)
01045 {
01046 float opacity;
01047 switch(rate)
01048 {
01049 case GradientConfig::LINEAR:
01050 if(mag < in_radius)
01051 opacity = 0.0;
01052 else
01053 if(mag >= out_radius)
01054 opacity = 1.0;
01055 else
01056 opacity = (float)(mag - in_radius) / (out_radius - in_radius);
01057 break;
01058
01059 case GradientConfig::LOG:
01060 if(mag < in_radius)
01061 opacity = 0;
01062 else
01063
01064 opacity = 1 - exp(1.0 * -(float)(mag - in_radius) /
01065 (out_radius - in_radius));
01066 break;
01067
01068 case GradientConfig::SQUARE:
01069 if(mag < in_radius)
01070 opacity = 0.0;
01071 else
01072 if(mag >= out_radius)
01073 opacity = 1.0;
01074 else
01075 opacity = powf((float)(mag - in_radius) /
01076 (out_radius - in_radius), 2.0);
01077 break;
01078 }
01079 CLAMP(opacity, 0.0, 1.0);
01080 return opacity;
01081 }
01082
01083 #define CREATE_GRADIENT(type, temp, components, max) \
01084 { \
01085 \
01086 \
01087 r_table = malloc(sizeof(type) * gradient_size); \
01088 g_table = malloc(sizeof(type) * gradient_size); \
01089 b_table = malloc(sizeof(type) * gradient_size); \
01090 a_table = malloc(sizeof(type) * gradient_size); \
01091 \
01092 for(int i = 0; i < gradient_size; i++) \
01093 { \
01094 float opacity = calculate_opacity(i, in_radius, out_radius, plugin->config.rate); \
01095 float transparency; \
01096 \
01097 transparency = 1.0 - opacity; \
01098 ((type*)r_table)[i] = (type)(out1 * opacity + in1 * transparency); \
01099 ((type*)g_table)[i] = (type)(out2 * opacity + in2 * transparency); \
01100 ((type*)b_table)[i] = (type)(out3 * opacity + in3 * transparency); \
01101 ((type*)a_table)[i] = (type)(out4 * opacity + in4 * transparency); \
01102 } \
01103 \
01104 for(int i = pkg->y1; i < pkg->y2; i++) \
01105 { \
01106 type *gradient_row = (type*)plugin->gradient->get_rows()[i]; \
01107 type *out_row = (type*)plugin->get_output()->get_rows()[i]; \
01108 \
01109 switch(plugin->config.shape) \
01110 { \
01111 case GradientConfig::LINEAR: \
01112 for(int j = 0; j < w; j++) \
01113 { \
01114 int x = j - half_w; \
01115 int y = -(i - half_h); \
01116 \
01117 \
01118 int mag = (int)(gradient_size / 2 - \
01119 (x * sin_angle + y * cos_angle) + \
01120 0.5); \
01121 \
01122 \
01123 \
01124 if(sizeof(type) == 4) \
01125 { \
01126 float opacity = calculate_opacity(mag, \
01127 in_radius, \
01128 out_radius, \
01129 plugin->config.rate); \
01130 float transparency = 1.0 - opacity; \
01131 gradient_row[0] = (type)(out1 * opacity + in1 * transparency); \
01132 gradient_row[1] = (type)(out2 * opacity + in2 * transparency); \
01133 gradient_row[2] = (type)(out3 * opacity + in3 * transparency); \
01134 if(components == 4) gradient_row[3] = (type)(out4 * opacity + in4 * transparency); \
01135 } \
01136 else \
01137 if(mag < 0) \
01138 { \
01139 gradient_row[0] = out1; \
01140 gradient_row[1] = out2; \
01141 gradient_row[2] = out3; \
01142 if(components == 4) gradient_row[3] = out4; \
01143 } \
01144 else \
01145 if(mag >= gradient_size) \
01146 { \
01147 gradient_row[0] = in1; \
01148 gradient_row[1] = in2; \
01149 gradient_row[2] = in3; \
01150 if(components == 4) gradient_row[3] = in4; \
01151 } \
01152 else \
01153 { \
01154 gradient_row[0] = ((type*)r_table)[mag]; \
01155 gradient_row[1] = ((type*)g_table)[mag]; \
01156 gradient_row[2] = ((type*)b_table)[mag]; \
01157 if(components == 4) gradient_row[3] = ((type*)a_table)[mag]; \
01158 } \
01159 \
01160 \
01161 if(gradient_cmodel != output_cmodel) \
01162 { \
01163 temp opacity = gradient_row[3]; \
01164 temp transparency = max - opacity; \
01165 out_row[0] = (transparency * out_row[0] + opacity * gradient_row[0]) / max; \
01166 out_row[1] = (transparency * out_row[1] + opacity * gradient_row[1]) / max; \
01167 out_row[2] = (transparency * out_row[2] + opacity * gradient_row[2]) / max; \
01168 out_row += 3; \
01169 } \
01170 \
01171 gradient_row += components; \
01172 } \
01173 break; \
01174 \
01175 case GradientConfig::RADIAL: \
01176 for(int j = 0; j < w; j++) \
01177 { \
01178 double x = j - center_x; \
01179 double y = i - center_y; \
01180 double magnitude = hypot(x, y); \
01181 int mag = (int)magnitude; \
01182 if(sizeof(type) == 4) \
01183 { \
01184 float opacity = calculate_opacity(mag, \
01185 in_radius, \
01186 out_radius, \
01187 plugin->config.rate); \
01188 float transparency = 1.0 - opacity; \
01189 gradient_row[0] = (type)(out1 * opacity + in1 * transparency); \
01190 gradient_row[1] = (type)(out2 * opacity + in2 * transparency); \
01191 gradient_row[2] = (type)(out3 * opacity + in3 * transparency); \
01192 if(components == 4) gradient_row[3] = (type)(out4 * opacity + in4 * transparency); \
01193 } \
01194 else \
01195 { \
01196 gradient_row[0] = ((type*)r_table)[mag]; \
01197 gradient_row[1] = ((type*)g_table)[mag]; \
01198 gradient_row[2] = ((type*)b_table)[mag]; \
01199 if(components == 4) gradient_row[3] = ((type*)a_table)[mag]; \
01200 } \
01201 \
01202 \
01203 if(gradient_cmodel != output_cmodel) \
01204 { \
01205 temp opacity = gradient_row[3]; \
01206 temp transparency = max - opacity; \
01207 out_row[0] = (transparency * out_row[0] + opacity * gradient_row[0]) / max; \
01208 out_row[1] = (transparency * out_row[1] + opacity * gradient_row[1]) / max; \
01209 out_row[2] = (transparency * out_row[2] + opacity * gradient_row[2]) / max; \
01210 out_row += 3; \
01211 } \
01212 \
01213 gradient_row += components; \
01214 } \
01215 break; \
01216 } \
01217 } \
01218 }
01219
01220 void GradientUnit::process_package(LoadPackage *package)
01221 {
01222 GradientPackage *pkg = (GradientPackage*)package;
01223 int h = plugin->input->get_h();
01224 int w = plugin->input->get_w();
01225 int half_w = w / 2;
01226 int half_h = h / 2;
01227 int gradient_size = (int)(ceil(hypot(w, h)));
01228 int in_radius = (int)(plugin->config.in_radius / 100 * gradient_size);
01229 int out_radius = (int)(plugin->config.out_radius / 100 * gradient_size);
01230 double sin_angle = sin(plugin->config.angle * (M_PI / 180));
01231 double cos_angle = cos(plugin->config.angle * (M_PI / 180));
01232 double center_x = plugin->config.center_x * w / 100;
01233 double center_y = plugin->config.center_y * h / 100;
01234 void *r_table = 0;
01235 void *g_table = 0;
01236 void *b_table = 0;
01237 void *a_table = 0;
01238 int gradient_cmodel = plugin->gradient->get_color_model();
01239 int output_cmodel = plugin->get_output()->get_color_model();
01240
01241 if(in_radius > out_radius)
01242 {
01243 in_radius ^= out_radius;
01244 out_radius ^= in_radius;
01245 in_radius ^= out_radius;
01246 }
01247
01248
01249 switch(gradient_cmodel)
01250 {
01251 case BC_RGB888:
01252 {
01253 int in1 = plugin->config.in_r;
01254 int in2 = plugin->config.in_g;
01255 int in3 = plugin->config.in_b;
01256 int in4 = plugin->config.in_a;
01257 int out1 = plugin->config.out_r;
01258 int out2 = plugin->config.out_g;
01259 int out3 = plugin->config.out_b;
01260 int out4 = plugin->config.out_a;
01261 CREATE_GRADIENT(unsigned char, int, 3, 0xff)
01262 break;
01263 }
01264
01265 case BC_RGBA8888:
01266 {
01267 int in1 = plugin->config.in_r;
01268 int in2 = plugin->config.in_g;
01269 int in3 = plugin->config.in_b;
01270 int in4 = plugin->config.in_a;
01271 int out1 = plugin->config.out_r;
01272 int out2 = plugin->config.out_g;
01273 int out3 = plugin->config.out_b;
01274 int out4 = plugin->config.out_a;
01275 CREATE_GRADIENT(unsigned char, int, 4, 0xff)
01276 break;
01277 }
01278
01279 case BC_RGB_FLOAT:
01280 {
01281 float in1 = (float)plugin->config.in_r / 0xff;
01282 float in2 = (float)plugin->config.in_g / 0xff;
01283 float in3 = (float)plugin->config.in_b / 0xff;
01284 float in4 = (float)plugin->config.in_a / 0xff;
01285 float out1 = (float)plugin->config.out_r / 0xff;
01286 float out2 = (float)plugin->config.out_g / 0xff;
01287 float out3 = (float)plugin->config.out_b / 0xff;
01288 float out4 = (float)plugin->config.out_a / 0xff;
01289 CREATE_GRADIENT(float, float, 3, 1.0)
01290 break;
01291 }
01292
01293 case BC_RGBA_FLOAT:
01294 {
01295 float in1 = (float)plugin->config.in_r / 0xff;
01296 float in2 = (float)plugin->config.in_g / 0xff;
01297 float in3 = (float)plugin->config.in_b / 0xff;
01298 float in4 = (float)plugin->config.in_a / 0xff;
01299 float out1 = (float)plugin->config.out_r / 0xff;
01300 float out2 = (float)plugin->config.out_g / 0xff;
01301 float out3 = (float)plugin->config.out_b / 0xff;
01302 float out4 = (float)plugin->config.out_a / 0xff;
01303 CREATE_GRADIENT(float, float, 4, 1.0)
01304 break;
01305 }
01306
01307 case BC_YUV888:
01308 {
01309 int in1, in2, in3, in4;
01310 int out1, out2, out3, out4;
01311 yuv.rgb_to_yuv_8(plugin->config.in_r,
01312 plugin->config.in_g,
01313 plugin->config.in_b,
01314 in1,
01315 in2,
01316 in3);
01317 in4 = plugin->config.in_a;
01318 yuv.rgb_to_yuv_8(plugin->config.out_r,
01319 plugin->config.out_g,
01320 plugin->config.out_b,
01321 out1,
01322 out2,
01323 out3);
01324 out4 = plugin->config.out_a;
01325 CREATE_GRADIENT(unsigned char, int, 3, 0xff)
01326 break;
01327 }
01328
01329 case BC_YUVA8888:
01330 {
01331 int in1, in2, in3, in4;
01332 int out1, out2, out3, out4;
01333 yuv.rgb_to_yuv_8(plugin->config.in_r,
01334 plugin->config.in_g,
01335 plugin->config.in_b,
01336 in1,
01337 in2,
01338 in3);
01339 in4 = plugin->config.in_a;
01340 yuv.rgb_to_yuv_8(plugin->config.out_r,
01341 plugin->config.out_g,
01342 plugin->config.out_b,
01343 out1,
01344 out2,
01345 out3);
01346 out4 = plugin->config.out_a;
01347 CREATE_GRADIENT(unsigned char, int, 4, 0xff)
01348 break;
01349 }
01350 }
01351
01352 if(r_table) free(r_table);
01353 if(g_table) free(g_table);
01354 if(b_table) free(b_table);
01355 if(a_table) free(a_table);
01356 }
01357
01358
01359
01360
01361
01362
01363 GradientServer::GradientServer(GradientMain *plugin,
01364 int total_clients,
01365 int total_packages)
01366 : LoadServer(total_clients, total_packages)
01367 {
01368 this->plugin = plugin;
01369 }
01370
01371 void GradientServer::init_packages()
01372 {
01373 for(int i = 0; i < get_total_packages(); i++)
01374 {
01375 GradientPackage *package = (GradientPackage*)get_package(i);
01376 package->y1 = plugin->input->get_h() *
01377 i /
01378 get_total_packages();
01379 package->y2 = plugin->input->get_h() *
01380 (i + 1) /
01381 get_total_packages();
01382 }
01383 }
01384
01385 LoadClient* GradientServer::new_client()
01386 {
01387 return new GradientUnit(this, plugin);
01388 }
01389
01390 LoadPackage* GradientServer::new_package()
01391 {
01392 return new GradientPackage;
01393 }
01394
01395
01396
01397
01398