00001 #include "../motion/affine.h"
00002 #include "bcdisplayinfo.h"
00003 #include "clip.h"
00004 #include "bchash.h"
00005 #include "filexml.h"
00006 #include "guicast.h"
00007 #include "language.h"
00008 #include "picon_png.h"
00009 #include "pluginvclient.h"
00010 #include "rotateframe.h"
00011 #include "vframe.h"
00012
00013
00014 #include <string.h>
00015
00016
00017
00018 #define SQR(x) ((x) * (x))
00019 #define MAXANGLE 360
00020
00021
00022 class RotateEffect;
00023 class RotateWindow;
00024
00025
00026 class RotateConfig
00027 {
00028 public:
00029 RotateConfig();
00030
00031 int equivalent(RotateConfig &that);
00032 void copy_from(RotateConfig &that);
00033 void interpolate(RotateConfig &prev,
00034 RotateConfig &next,
00035 long prev_frame,
00036 long next_frame,
00037 long current_frame);
00038
00039 float angle;
00040 float pivot_x;
00041 float pivot_y;
00042 int draw_pivot;
00043
00044 };
00045
00046 class RotateToggle : public BC_Radial
00047 {
00048 public:
00049 RotateToggle(RotateWindow *window,
00050 RotateEffect *plugin,
00051 int init_value,
00052 int x,
00053 int y,
00054 int value,
00055 char *string);
00056 int handle_event();
00057
00058 RotateEffect *plugin;
00059 RotateWindow *window;
00060 int value;
00061 };
00062
00063 class RotateDrawPivot : public BC_CheckBox
00064 {
00065 public:
00066 RotateDrawPivot(RotateWindow *window,
00067 RotateEffect *plugin,
00068 int x,
00069 int y);
00070 int handle_event();
00071 RotateEffect *plugin;
00072 RotateWindow *window;
00073 int value;
00074 };
00075
00076 class RotateInterpolate : public BC_CheckBox
00077 {
00078 public:
00079 RotateInterpolate(RotateEffect *plugin, int x, int y);
00080 int handle_event();
00081 RotateEffect *plugin;
00082 };
00083
00084 class RotateFine : public BC_FPot
00085 {
00086 public:
00087 RotateFine(RotateWindow *window,
00088 RotateEffect *plugin,
00089 int x,
00090 int y);
00091 int handle_event();
00092
00093 RotateEffect *plugin;
00094 RotateWindow *window;
00095 };
00096
00097 class RotateX : public BC_FPot
00098 {
00099 public:
00100 RotateX(RotateWindow *window,
00101 RotateEffect *plugin,
00102 int x,
00103 int y);
00104 int handle_event();
00105 RotateEffect *plugin;
00106 RotateWindow *window;
00107 };
00108
00109 class RotateY : public BC_FPot
00110 {
00111 public:
00112 RotateY(RotateWindow *window,
00113 RotateEffect *plugin,
00114 int x,
00115 int y);
00116 int handle_event();
00117 RotateEffect *plugin;
00118 RotateWindow *window;
00119 };
00120
00121
00122 class RotateText : public BC_TextBox
00123 {
00124 public:
00125 RotateText(RotateWindow *window,
00126 RotateEffect *plugin,
00127 int x,
00128 int y);
00129 int handle_event();
00130
00131 RotateEffect *plugin;
00132 RotateWindow *window;
00133 };
00134
00135 class RotateWindow : public BC_Window
00136 {
00137 public:
00138 RotateWindow(RotateEffect *plugin, int x, int y);
00139
00140 int create_objects();
00141 int close_event();
00142 int update();
00143 int update_fine();
00144 int update_text();
00145 int update_toggles();
00146
00147 RotateEffect *plugin;
00148 RotateToggle *toggle0;
00149 RotateToggle *toggle90;
00150 RotateToggle *toggle180;
00151 RotateToggle *toggle270;
00152 RotateDrawPivot *draw_pivot;
00153 RotateFine *fine;
00154 RotateText *text;
00155 RotateX *x;
00156 RotateY *y;
00157
00158 };
00159
00160
00161 PLUGIN_THREAD_HEADER(RotateEffect, RotateThread, RotateWindow)
00162
00163
00164 class RotateEffect : public PluginVClient
00165 {
00166 public:
00167 RotateEffect(PluginServer *server);
00168 ~RotateEffect();
00169
00170 int process_buffer(VFrame *frame,
00171 int64_t start_position,
00172 double frame_rate);
00173 int is_realtime();
00174 char* plugin_title();
00175 VFrame* new_picon();
00176 int show_gui();
00177 void raise_window();
00178 void update_gui();
00179 int set_string();
00180 int load_configuration();
00181 int load_defaults();
00182 int save_defaults();
00183 void save_data(KeyFrame *keyframe);
00184 void read_data(KeyFrame *keyframe);
00185 int handle_opengl();
00186
00187 RotateConfig config;
00188 AffineEngine *engine;
00189 RotateThread *thread;
00190 BC_Hash *defaults;
00191 int need_reconfigure;
00192 };
00193
00194
00195
00196
00197
00198
00199
00200 REGISTER_PLUGIN(RotateEffect)
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219 RotateConfig::RotateConfig()
00220 {
00221 angle = 0;
00222 pivot_x = 50;
00223 pivot_y = 50;
00224 draw_pivot = 0;
00225 }
00226
00227 int RotateConfig::equivalent(RotateConfig &that)
00228 {
00229 return EQUIV(angle, that.angle) &&
00230 EQUIV(pivot_x, that.pivot_y) &&
00231 EQUIV(pivot_y, that.pivot_y) &&
00232 draw_pivot == that.draw_pivot;
00233 }
00234
00235 void RotateConfig::copy_from(RotateConfig &that)
00236 {
00237 angle = that.angle;
00238 pivot_x = that.pivot_x;
00239 pivot_y = that.pivot_y;
00240 draw_pivot = that.draw_pivot;
00241
00242 }
00243
00244 void RotateConfig::interpolate(RotateConfig &prev,
00245 RotateConfig &next,
00246 long prev_frame,
00247 long next_frame,
00248 long current_frame)
00249 {
00250 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
00251 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
00252
00253 this->angle = prev.angle * prev_scale + next.angle * next_scale;
00254 this->pivot_x = prev.pivot_x * prev_scale + next.pivot_x * next_scale;
00255 this->pivot_y = prev.pivot_y * prev_scale + next.pivot_y * next_scale;
00256 draw_pivot = prev.draw_pivot;
00257
00258 }
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270 RotateToggle::RotateToggle(RotateWindow *window,
00271 RotateEffect *plugin,
00272 int init_value,
00273 int x,
00274 int y,
00275 int value,
00276 char *string)
00277 : BC_Radial(x, y, init_value, string)
00278 {
00279 this->value = value;
00280 this->plugin = plugin;
00281 this->window = window;
00282 }
00283
00284 int RotateToggle::handle_event()
00285 {
00286 plugin->config.angle = (float)value;
00287 window->update();
00288 plugin->send_configure_change();
00289 return 1;
00290 }
00291
00292
00293
00294
00295
00296
00297
00298 RotateDrawPivot::RotateDrawPivot(RotateWindow *window,
00299 RotateEffect *plugin,
00300 int x,
00301 int y)
00302 : BC_CheckBox(x, y, plugin->config.draw_pivot, _("Draw pivot"))
00303 {
00304 this->plugin = plugin;
00305 this->window = window;
00306 }
00307
00308 int RotateDrawPivot::handle_event()
00309 {
00310 plugin->config.draw_pivot = get_value();
00311 plugin->send_configure_change();
00312 return 1;
00313 }
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334 RotateFine::RotateFine(RotateWindow *window, RotateEffect *plugin, int x, int y)
00335 : BC_FPot(x,
00336 y,
00337 (float)plugin->config.angle,
00338 (float)-360,
00339 (float)360)
00340 {
00341 this->window = window;
00342 this->plugin = plugin;
00343 set_precision(0.01);
00344 set_use_caption(0);
00345 }
00346
00347 int RotateFine::handle_event()
00348 {
00349 plugin->config.angle = get_value();
00350 window->update_toggles();
00351 window->update_text();
00352 plugin->send_configure_change();
00353 return 1;
00354 }
00355
00356
00357
00358 RotateText::RotateText(RotateWindow *window,
00359 RotateEffect *plugin,
00360 int x,
00361 int y)
00362 : BC_TextBox(x,
00363 y,
00364 100,
00365 1,
00366 (float)plugin->config.angle)
00367 {
00368 this->window = window;
00369 this->plugin = plugin;
00370 set_precision(4);
00371 }
00372
00373 int RotateText::handle_event()
00374 {
00375 plugin->config.angle = atof(get_text());
00376 window->update_toggles();
00377 window->update_fine();
00378 plugin->send_configure_change();
00379 return 1;
00380 }
00381
00382
00383
00384 RotateX::RotateX(RotateWindow *window, RotateEffect *plugin, int x, int y)
00385 : BC_FPot(x,
00386 y,
00387 (float)plugin->config.pivot_x,
00388 (float)0,
00389 (float)100)
00390 {
00391 this->window = window;
00392 this->plugin = plugin;
00393 set_precision(0.01);
00394 set_use_caption(1);
00395 }
00396
00397 int RotateX::handle_event()
00398 {
00399 plugin->config.pivot_x = get_value();
00400 plugin->send_configure_change();
00401 return 1;
00402 }
00403
00404 RotateY::RotateY(RotateWindow *window, RotateEffect *plugin, int x, int y)
00405 : BC_FPot(x,
00406 y,
00407 (float)plugin->config.pivot_y,
00408 (float)0,
00409 (float)100)
00410 {
00411 this->window = window;
00412 this->plugin = plugin;
00413 set_precision(0.01);
00414 set_use_caption(1);
00415 }
00416
00417 int RotateY::handle_event()
00418 {
00419 plugin->config.pivot_y = get_value();
00420 plugin->send_configure_change();
00421 return 1;
00422 }
00423
00424
00425
00426
00427
00428
00429
00430
00431 RotateWindow::RotateWindow(RotateEffect *plugin, int x, int y)
00432 : BC_Window(plugin->gui_string,
00433 x,
00434 y,
00435 250,
00436 230,
00437 250,
00438 230,
00439 0,
00440 0,
00441 1)
00442 {
00443 this->plugin = plugin;
00444 }
00445
00446 #define RADIUS 30
00447
00448 int RotateWindow::create_objects()
00449 {
00450 int x = 10, y = 10;
00451 BC_Title *title;
00452
00453
00454
00455 add_tool(new BC_Title(x, y, _("Rotate")));
00456 x += 50;
00457 y += 20;
00458 add_tool(toggle0 = new RotateToggle(this,
00459 plugin,
00460 plugin->config.angle == 0,
00461 x,
00462 y,
00463 0,
00464 "0"));
00465 x += RADIUS;
00466 y += RADIUS;
00467 add_tool(toggle90 = new RotateToggle(this,
00468 plugin,
00469 plugin->config.angle == 90,
00470 x,
00471 y,
00472 90,
00473 "90"));
00474 x -= RADIUS;
00475 y += RADIUS;
00476 add_tool(toggle180 = new RotateToggle(this,
00477 plugin,
00478 plugin->config.angle == 180,
00479 x,
00480 y,
00481 180,
00482 "180"));
00483 x -= RADIUS;
00484 y -= RADIUS;
00485 add_tool(toggle270 = new RotateToggle(this,
00486 plugin,
00487 plugin->config.angle == 270,
00488 x,
00489 y,
00490 270,
00491 "270"));
00492
00493 x += 120;
00494 y -= 50;
00495 add_tool(fine = new RotateFine(this, plugin, x, y));
00496 y += fine->get_h() + 10;
00497 add_tool(text = new RotateText(this, plugin, x, y));
00498 y += 30;
00499 add_tool(new BC_Title(x, y, _("Degrees")));
00500
00501
00502
00503
00504
00505 y += text->get_h() + 10;
00506 add_subwindow(title = new BC_Title(x, y, _("Pivot (x,y):")));
00507 y += title->get_h() + 10;
00508 add_subwindow(this->x = new RotateX(this, plugin, x, y));
00509 x += this->x->get_w() + 10;
00510 add_subwindow(this->y = new RotateY(this, plugin, x, y));
00511
00512 x = 10;
00513 y += this->y->get_h() + 10;
00514 add_subwindow(draw_pivot = new RotateDrawPivot(this, plugin, x, y));
00515
00516 show_window();
00517 flush();
00518
00519
00520
00521 return 0;
00522 }
00523
00524 WINDOW_CLOSE_EVENT(RotateWindow)
00525
00526 int RotateWindow::update()
00527 {
00528 update_fine();
00529 update_toggles();
00530 update_text();
00531
00532 return 0;
00533 }
00534
00535 int RotateWindow::update_fine()
00536 {
00537 fine->update(plugin->config.angle);
00538 x->update(plugin->config.pivot_x);
00539 y->update(plugin->config.pivot_y);
00540 return 0;
00541 }
00542
00543 int RotateWindow::update_text()
00544 {
00545 text->update(plugin->config.angle);
00546 return 0;
00547 }
00548
00549 int RotateWindow::update_toggles()
00550 {
00551 toggle0->update(EQUIV(plugin->config.angle, 0));
00552 toggle90->update(EQUIV(plugin->config.angle, 90));
00553 toggle180->update(EQUIV(plugin->config.angle, 180));
00554 toggle270->update(EQUIV(plugin->config.angle, 270));
00555 draw_pivot->update(plugin->config.draw_pivot);
00556 return 0;
00557 }
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573 PLUGIN_THREAD_OBJECT(RotateEffect, RotateThread, RotateWindow)
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592 RotateEffect::RotateEffect(PluginServer *server)
00593 : PluginVClient(server)
00594 {
00595 engine = 0;
00596 need_reconfigure = 1;
00597 PLUGIN_CONSTRUCTOR_MACRO
00598 }
00599
00600 RotateEffect::~RotateEffect()
00601 {
00602 PLUGIN_DESTRUCTOR_MACRO
00603 if(engine) delete engine;
00604 }
00605
00606
00607
00608 char* RotateEffect::plugin_title() { return N_("Rotate"); }
00609 int RotateEffect::is_realtime() { return 1; }
00610
00611 NEW_PICON_MACRO(RotateEffect)
00612
00613 SET_STRING_MACRO(RotateEffect)
00614
00615 SHOW_GUI_MACRO(RotateEffect, RotateThread)
00616
00617 RAISE_WINDOW_MACRO(RotateEffect)
00618
00619
00620 void RotateEffect::update_gui()
00621 {
00622 if(thread)
00623 {
00624 load_configuration();
00625 thread->window->lock_window();
00626 thread->window->update();
00627 thread->window->unlock_window();
00628 }
00629 }
00630
00631 LOAD_CONFIGURATION_MACRO(RotateEffect, RotateConfig)
00632
00633
00634
00635 int RotateEffect::load_defaults()
00636 {
00637 char directory[1024], string[1024];
00638
00639 sprintf(directory, "%srotate.rc", BCASTDIR);
00640
00641
00642 defaults = new BC_Hash(directory);
00643 defaults->load();
00644
00645 config.angle = defaults->get("ANGLE", (float)config.angle);
00646 config.pivot_x = defaults->get("PIVOT_X", (float)config.pivot_x);
00647 config.pivot_y = defaults->get("PIVOT_Y", (float)config.pivot_y);
00648 config.draw_pivot = defaults->get("DRAW_PIVOT", (int)config.draw_pivot);
00649
00650 return 0;
00651 }
00652
00653 int RotateEffect::save_defaults()
00654 {
00655 defaults->update("ANGLE", (float)config.angle);
00656 defaults->update("PIVOT_X", (float)config.pivot_x);
00657 defaults->update("PIVOT_Y", (float)config.pivot_y);
00658 defaults->update("DRAW_PIVOT", (int)config.draw_pivot);
00659
00660 defaults->save();
00661 return 0;
00662 }
00663
00664 void RotateEffect::save_data(KeyFrame *keyframe)
00665 {
00666 FileXML output;
00667
00668
00669 output.set_shared_string(keyframe->data, MESSAGESIZE);
00670 output.tag.set_title("ROTATE");
00671 output.tag.set_property("ANGLE", (float)config.angle);
00672 output.tag.set_property("PIVOT_X", (float)config.pivot_x);
00673 output.tag.set_property("PIVOT_Y", (float)config.pivot_y);
00674 output.tag.set_property("DRAW_PIVOT", (int)config.draw_pivot);
00675
00676 output.append_tag();
00677 output.tag.set_title("/ROTATE");
00678 output.append_tag();
00679 output.terminate_string();
00680
00681 }
00682
00683 void RotateEffect::read_data(KeyFrame *keyframe)
00684 {
00685 FileXML input;
00686
00687 input.set_shared_string(keyframe->data, strlen(keyframe->data));
00688
00689 int result = 0;
00690
00691 while(!result)
00692 {
00693 result = input.read_tag();
00694
00695 if(!result)
00696 {
00697 if(input.tag.title_is("ROTATE"))
00698 {
00699 config.angle = input.tag.get_property("ANGLE", (float)config.angle);
00700 config.pivot_x = input.tag.get_property("PIVOT_X", (float)config.pivot_x);
00701 config.pivot_y = input.tag.get_property("PIVOT_Y", (float)config.pivot_y);
00702 config.draw_pivot = input.tag.get_property("DRAW_PIVOT", (int)config.draw_pivot);
00703
00704 }
00705 }
00706 }
00707 }
00708
00709 int RotateEffect::process_buffer(VFrame *frame,
00710 int64_t start_position,
00711 double frame_rate)
00712 {
00713 load_configuration();
00714 int w = frame->get_w();
00715 int h = frame->get_h();
00716
00717
00718
00719 if(config.angle == 0)
00720 {
00721 read_frame(frame,
00722 0,
00723 start_position,
00724 frame_rate,
00725 get_use_opengl());
00726 return 1;
00727 }
00728
00729 if(!engine) engine = new AffineEngine(PluginClient::smp + 1,
00730 PluginClient::smp + 1);
00731 engine->set_pivot((int)(config.pivot_x * get_input()->get_w() / 100),
00732 (int)(config.pivot_y * get_input()->get_h() / 100));
00733
00734 if(get_use_opengl())
00735 {
00736 read_frame(frame,
00737 0,
00738 start_position,
00739 frame_rate,
00740 get_use_opengl());
00741 return run_opengl();
00742 }
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752 VFrame *temp_frame = PluginVClient::new_temp(get_input()->get_w(),
00753 get_input()->get_h(),
00754 get_input()->get_color_model());
00755 read_frame(temp_frame,
00756 0,
00757 start_position,
00758 frame_rate,
00759 get_use_opengl());
00760 frame->clear_frame();
00761 engine->rotate(frame,
00762 temp_frame,
00763 config.angle);
00764
00765
00766
00767 #define CENTER_H 20
00768 #define CENTER_W 20
00769 #define DRAW_CENTER(components, type, max) \
00770 { \
00771 type **rows = (type**)get_output()->get_rows(); \
00772 if(center_x >= 0 && center_x < w || \
00773 center_y >= 0 && center_y < h) \
00774 { \
00775 type *hrow = rows[center_y] + components * (center_x - CENTER_W / 2); \
00776 for(int i = center_x - CENTER_W / 2; i <= center_x + CENTER_W / 2; i++) \
00777 { \
00778 if(i >= 0 && i < w) \
00779 { \
00780 hrow[0] = max - hrow[0]; \
00781 hrow[1] = max - hrow[1]; \
00782 hrow[2] = max - hrow[2]; \
00783 hrow += components; \
00784 } \
00785 } \
00786 \
00787 for(int i = center_y - CENTER_W / 2; i <= center_y + CENTER_W / 2; i++) \
00788 { \
00789 if(i >= 0 && i < h) \
00790 { \
00791 type *vrow = rows[i] + center_x * components; \
00792 vrow[0] = max - vrow[0]; \
00793 vrow[1] = max - vrow[1]; \
00794 vrow[2] = max - vrow[2]; \
00795 } \
00796 } \
00797 } \
00798 }
00799
00800 if(config.draw_pivot)
00801 {
00802 int center_x = (int)(config.pivot_x * w / 100); \
00803 int center_y = (int)(config.pivot_y * h / 100); \
00804 switch(get_output()->get_color_model())
00805 {
00806 case BC_RGB_FLOAT:
00807 DRAW_CENTER(3, float, 1.0)
00808 break;
00809 case BC_RGBA_FLOAT:
00810 DRAW_CENTER(4, float, 1.0)
00811 break;
00812 case BC_RGB888:
00813 DRAW_CENTER(3, unsigned char, 0xff)
00814 break;
00815 case BC_RGBA8888:
00816 DRAW_CENTER(4, unsigned char, 0xff)
00817 break;
00818 case BC_YUV888:
00819 DRAW_CENTER(3, unsigned char, 0xff)
00820 break;
00821 case BC_YUVA8888:
00822 DRAW_CENTER(4, unsigned char, 0xff)
00823 break;
00824 }
00825 }
00826
00827
00828 if(get_input()->get_w() > PLUGIN_MAX_W &&
00829 get_input()->get_h() > PLUGIN_MAX_H)
00830 {
00831 delete engine;
00832 engine = 0;
00833 }
00834 return 0;
00835 }
00836
00837
00838
00839 int RotateEffect::handle_opengl()
00840 {
00841 #ifdef HAVE_GL
00842 engine->set_opengl(1);
00843 engine->rotate(get_output(),
00844 get_output(),
00845 config.angle);
00846 engine->set_opengl(0);
00847
00848 if(config.draw_pivot)
00849 {
00850 int w = get_output()->get_w();
00851 int h = get_output()->get_h();
00852 int center_x = (int)(config.pivot_x * w / 100); \
00853 int center_y = (int)(config.pivot_y * h / 100); \
00854
00855 glDisable(GL_TEXTURE_2D);
00856 glColor4f(1.0, 1.0, 1.0, 1.0);
00857 glLogicOp(GL_XOR);
00858 glEnable(GL_COLOR_LOGIC_OP);
00859 glBegin(GL_LINES);
00860 glVertex3f(center_x, -h + center_y - CENTER_H / 2, 0.0);
00861 glVertex3f(center_x, -h + center_y + CENTER_H / 2, 0.0);
00862 glEnd();
00863 glBegin(GL_LINES);
00864 glVertex3f(center_x - CENTER_W / 2, -h + center_y, 0.0);
00865 glVertex3f(center_x + CENTER_W / 2, -h + center_y, 0.0);
00866 glEnd();
00867 glDisable(GL_COLOR_LOGIC_OP);
00868 }
00869 #endif
00870 }
00871
00872