remaining effects, radialblur, rotate
[cinelerra_cv/ct.git] / plugins / rotate / rotate.C
blobb12b20bd866e21ea835ae16911426c196cbe87cb
1 #include "affine.h"
2 #include "bcdisplayinfo.h"
3 #include "clip.h"
4 #include "bchash.h"
5 #include "filexml.h"
6 #include "guicast.h"
7 #include "language.h"
8 #include "picon_png.h"
9 #include "pluginvclient.h"
10 #include "rotateframe.h"
11 #include "vframe.h"
14 #include <string.h>
18 #define SQR(x) ((x) * (x))
19 #define MAXANGLE 360
22 class RotateEffect;
23 class RotateWindow;
26 class RotateConfig
28 public:
29         RotateConfig();
31         int equivalent(RotateConfig &that);
32         void copy_from(RotateConfig &that);
33         void interpolate(RotateConfig &prev, 
34                 RotateConfig &next, 
35                 long prev_frame, 
36                 long next_frame, 
37                 long current_frame);
39         float angle;
40         float pivot_x;
41         float pivot_y;
42         int draw_pivot;
43 //      int bilinear;
46 class RotateToggle : public BC_Radial
48 public:
49         RotateToggle(RotateWindow *window, 
50                 RotateEffect *plugin, 
51                 int init_value, 
52                 int x, 
53                 int y, 
54                 int value, 
55                 char *string);
56         int handle_event();
58         RotateEffect *plugin;
59     RotateWindow *window;
60     int value;
63 class RotateDrawPivot : public BC_CheckBox
65 public:
66         RotateDrawPivot(RotateWindow *window, 
67                 RotateEffect *plugin, 
68                 int x, 
69                 int y);
70         int handle_event();
71         RotateEffect *plugin;
72     RotateWindow *window;
73     int value;
76 class RotateInterpolate : public BC_CheckBox
78 public:
79         RotateInterpolate(RotateEffect *plugin, int x, int y);
80         int handle_event();
81         RotateEffect *plugin;
84 class RotateFine : public BC_FPot
86 public:
87         RotateFine(RotateWindow *window, 
88                 RotateEffect *plugin, 
89                 int x, 
90                 int y);
91         int handle_event();
93         RotateEffect *plugin;
94     RotateWindow *window;
97 class RotateX : public BC_FPot
99 public:
100         RotateX(RotateWindow *window, 
101                 RotateEffect *plugin, 
102                 int x, 
103                 int y);
104         int handle_event();
105         RotateEffect *plugin;
106     RotateWindow *window;
109 class RotateY : public BC_FPot
111 public:
112         RotateY(RotateWindow *window, 
113                 RotateEffect *plugin, 
114                 int x, 
115                 int y);
116         int handle_event();
117         RotateEffect *plugin;
118     RotateWindow *window;
122 class RotateText : public BC_TextBox
124 public:
125         RotateText(RotateWindow *window, 
126                 RotateEffect *plugin, 
127                 int x, 
128                 int y);
129         int handle_event();
131         RotateEffect *plugin;
132     RotateWindow *window;
135 class RotateWindow : public BC_Window
137 public:
138         RotateWindow(RotateEffect *plugin, int x, int y);
140         int create_objects();
141         int close_event();
142         int update();
143         int update_fine();
144         int update_text();
145         int update_toggles();
147         RotateEffect *plugin;
148         RotateToggle *toggle0;
149         RotateToggle *toggle90;
150         RotateToggle *toggle180;
151         RotateToggle *toggle270;
152         RotateDrawPivot *draw_pivot;
153         RotateFine *fine;
154         RotateText *text;
155         RotateX *x;
156         RotateY *y;
157 //      RotateInterpolate *bilinear;
161 PLUGIN_THREAD_HEADER(RotateEffect, RotateThread, RotateWindow)
164 class RotateEffect : public PluginVClient
166 public:
167         RotateEffect(PluginServer *server);
168         ~RotateEffect();
169         
170         int process_buffer(VFrame *frame,
171                 int64_t start_position,
172                 double frame_rate);
173         int is_realtime();
174         char* plugin_title();
175         VFrame* new_picon();
176         int show_gui();
177         void raise_window();
178         void update_gui();
179         int set_string();
180         int load_configuration();
181         int load_defaults();
182         int save_defaults();
183         void save_data(KeyFrame *keyframe);
184         void read_data(KeyFrame *keyframe);
185         int handle_opengl();
187         RotateConfig config;
188         AffineEngine *engine;
189         RotateThread *thread;
190         BC_Hash *defaults;
191         int need_reconfigure;
200 REGISTER_PLUGIN(RotateEffect)
219 RotateConfig::RotateConfig()
221         angle = 0;
222         pivot_x = 50;
223         pivot_y = 50;
224         draw_pivot = 0;
227 int RotateConfig::equivalent(RotateConfig &that)
229         return EQUIV(angle, that.angle) &&
230                 EQUIV(pivot_x, that.pivot_y) &&
231                 EQUIV(pivot_y, that.pivot_y) &&
232                 draw_pivot == that.draw_pivot;
235 void RotateConfig::copy_from(RotateConfig &that)
237         angle = that.angle;
238         pivot_x = that.pivot_x;
239         pivot_y = that.pivot_y;
240         draw_pivot = that.draw_pivot;
241 //      bilinear = that.bilinear;
244 void RotateConfig::interpolate(RotateConfig &prev, 
245                 RotateConfig &next, 
246                 long prev_frame, 
247                 long next_frame, 
248                 long current_frame)
250         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
251         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
253         this->angle = prev.angle * prev_scale + next.angle * next_scale;
254         this->pivot_x = prev.pivot_x * prev_scale + next.pivot_x * next_scale;
255         this->pivot_y = prev.pivot_y * prev_scale + next.pivot_y * next_scale;
256         draw_pivot = prev.draw_pivot;
257 //      bilinear = prev.bilinear;
270 RotateToggle::RotateToggle(RotateWindow *window, 
271         RotateEffect *plugin, 
272         int init_value, 
273         int x, 
274         int y, 
275         int value, 
276         char *string)
277  : BC_Radial(x, y, init_value, string)
279         this->value = value;
280         this->plugin = plugin;
281     this->window = window;
284 int RotateToggle::handle_event()
286         plugin->config.angle = (float)value;
287     window->update();
288         plugin->send_configure_change();
289         return 1;
298 RotateDrawPivot::RotateDrawPivot(RotateWindow *window, 
299         RotateEffect *plugin, 
300         int x, 
301         int y)
302  : BC_CheckBox(x, y, plugin->config.draw_pivot, _("Draw pivot"))
304         this->plugin = plugin;
305     this->window = window;
308 int RotateDrawPivot::handle_event()
310         plugin->config.draw_pivot = get_value();
311         plugin->send_configure_change();
312         return 1;
319 // RotateInterpolate::RotateInterpolate(RotateEffect *plugin, int x, int y)
320 //  : BC_CheckBox(x, y, plugin->config.bilinear, _("Interpolate"))
321 // {
322 //      this->plugin = plugin;
323 // }
324 // int RotateInterpolate::handle_event()
325 // {
326 //      plugin->config.bilinear = get_value();
327 //      plugin->send_configure_change();
328 //      return 1;
329 // }
330 // 
334 RotateFine::RotateFine(RotateWindow *window, RotateEffect *plugin, int x, int y)
335  : BC_FPot(x, 
336         y, 
337         (float)plugin->config.angle, 
338         (float)-360, 
339         (float)360)
341         this->window = window;
342         this->plugin = plugin;
343         set_precision(0.01);
344         set_use_caption(0);
347 int RotateFine::handle_event()
349         plugin->config.angle = get_value();
350         window->update_toggles();
351         window->update_text();
352         plugin->send_configure_change();
353         return 1;
358 RotateText::RotateText(RotateWindow *window, 
359         RotateEffect *plugin, 
360         int x, 
361         int y)
362  : BC_TextBox(x, 
363         y, 
364         100,
365         1,
366         (float)plugin->config.angle)
368         this->window = window;
369         this->plugin = plugin;
370         set_precision(4);
373 int RotateText::handle_event()
375         plugin->config.angle = atof(get_text());
376         window->update_toggles();
377         window->update_fine();
378         plugin->send_configure_change();
379         return 1;
384 RotateX::RotateX(RotateWindow *window, RotateEffect *plugin, int x, int y)
385  : BC_FPot(x, 
386         y, 
387         (float)plugin->config.pivot_x, 
388         (float)0, 
389         (float)100)
391         this->window = window;
392         this->plugin = plugin;
393         set_precision(0.01);
394         set_use_caption(1);
397 int RotateX::handle_event()
399         plugin->config.pivot_x = get_value();
400         plugin->send_configure_change();
401         return 1;
404 RotateY::RotateY(RotateWindow *window, RotateEffect *plugin, int x, int y)
405  : BC_FPot(x, 
406         y, 
407         (float)plugin->config.pivot_y, 
408         (float)0, 
409         (float)100)
411         this->window = window;
412         this->plugin = plugin;
413         set_precision(0.01);
414         set_use_caption(1);
417 int RotateY::handle_event()
419         plugin->config.pivot_y = get_value();
420         plugin->send_configure_change();
421         return 1;
431 RotateWindow::RotateWindow(RotateEffect *plugin, int x, int y)
432  : BC_Window(plugin->gui_string, 
433         x,
434         y,
435         250, 
436         230, 
437         250, 
438         230, 
439         0, 
440         0,
441         1)
443         this->plugin = plugin;
446 #define RADIUS 30
448 int RotateWindow::create_objects()
450         int x = 10, y = 10;
451         BC_Title *title;
455         add_tool(new BC_Title(x, y, _("Rotate")));
456         x += 50;
457         y += 20;
458         add_tool(toggle0 = new RotateToggle(this, 
459                 plugin, 
460                 plugin->config.angle == 0, 
461                 x, 
462                 y, 
463                 0, 
464                 "0"));
465     x += RADIUS;
466     y += RADIUS;
467         add_tool(toggle90 = new RotateToggle(this, 
468                 plugin, 
469                 plugin->config.angle == 90, 
470                 x, 
471                 y, 
472                 90, 
473                 "90"));
474     x -= RADIUS;
475     y += RADIUS;
476         add_tool(toggle180 = new RotateToggle(this, 
477                 plugin, 
478                 plugin->config.angle == 180, 
479                 x, 
480                 y, 
481                 180, 
482                 "180"));
483     x -= RADIUS;
484     y -= RADIUS;
485         add_tool(toggle270 = new RotateToggle(this, 
486                 plugin, 
487                 plugin->config.angle == 270, 
488                 x, 
489                 y, 
490                 270, 
491                 "270"));
492 //      add_subwindow(bilinear = new RotateInterpolate(plugin, 10, y + 60));
493         x += 120;
494         y -= 50;
495         add_tool(fine = new RotateFine(this, plugin, x, y));
496         y += fine->get_h() + 10;
497         add_tool(text = new RotateText(this, plugin, x, y));
498         y += 30;
499         add_tool(new BC_Title(x, y, _("Degrees")));
500         
505         y += text->get_h() + 10;
506         add_subwindow(title = new BC_Title(x, y, _("Pivot (x,y):")));
507         y += title->get_h() + 10;
508         add_subwindow(this->x = new RotateX(this, plugin, x, y));
509         x += this->x->get_w() + 10;
510         add_subwindow(this->y = new RotateY(this, plugin, x, y));
512         x = 10;
513         y += this->y->get_h() + 10;
514         add_subwindow(draw_pivot = new RotateDrawPivot(this, plugin, x, y));
516         show_window();
517         flush();
521         return 0;
524 WINDOW_CLOSE_EVENT(RotateWindow)
526 int RotateWindow::update()
528         update_fine();
529         update_toggles();
530         update_text();
531 //      bilinear->update(plugin->config.bilinear);
532         return 0;
535 int RotateWindow::update_fine()
537         fine->update(plugin->config.angle);
538         x->update(plugin->config.pivot_x);
539         y->update(plugin->config.pivot_y);
540         return 0;
543 int RotateWindow::update_text()
545         text->update(plugin->config.angle);
546         return 0;
549 int RotateWindow::update_toggles()
551         toggle0->update(EQUIV(plugin->config.angle, 0));
552         toggle90->update(EQUIV(plugin->config.angle, 90));
553         toggle180->update(EQUIV(plugin->config.angle, 180));
554         toggle270->update(EQUIV(plugin->config.angle, 270));
555         draw_pivot->update(plugin->config.draw_pivot);
556         return 0;
573 PLUGIN_THREAD_OBJECT(RotateEffect, RotateThread, RotateWindow)
592 RotateEffect::RotateEffect(PluginServer *server)
593  : PluginVClient(server)
595         engine = 0;
596         need_reconfigure = 1;
597         PLUGIN_CONSTRUCTOR_MACRO
600 RotateEffect::~RotateEffect()
602         PLUGIN_DESTRUCTOR_MACRO
603         if(engine) delete engine;
608 char* RotateEffect::plugin_title() { return N_("Rotate"); }
609 int RotateEffect::is_realtime() { return 1; }
611 NEW_PICON_MACRO(RotateEffect)
613 SET_STRING_MACRO(RotateEffect)
615 SHOW_GUI_MACRO(RotateEffect, RotateThread)
617 RAISE_WINDOW_MACRO(RotateEffect)
620 void RotateEffect::update_gui()
622         if(thread)
623         {
624                 load_configuration();
625                 thread->window->lock_window();
626                 thread->window->update();
627                 thread->window->unlock_window();
628         }
631 LOAD_CONFIGURATION_MACRO(RotateEffect, RotateConfig)
635 int RotateEffect::load_defaults()
637         char directory[1024], string[1024];
638 // set the default directory
639         sprintf(directory, "%srotate.rc", BCASTDIR);
641 // load the defaults
642         defaults = new BC_Hash(directory);
643         defaults->load();
645         config.angle = defaults->get("ANGLE", (float)config.angle);
646         config.pivot_x = defaults->get("PIVOT_X", (float)config.pivot_x);
647         config.pivot_y = defaults->get("PIVOT_Y", (float)config.pivot_y);
648         config.draw_pivot = defaults->get("DRAW_PIVOT", (int)config.draw_pivot);
649 //      config.bilinear = defaults->get("INTERPOLATE", (int)config.bilinear);
650         return 0;
653 int RotateEffect::save_defaults()
655         defaults->update("ANGLE", (float)config.angle);
656         defaults->update("PIVOT_X", (float)config.pivot_x);
657         defaults->update("PIVOT_Y", (float)config.pivot_y);
658         defaults->update("DRAW_PIVOT", (int)config.draw_pivot);
659 //      defaults->update("INTERPOLATE", (int)config.bilinear);
660         defaults->save();
661         return 0;
664 void RotateEffect::save_data(KeyFrame *keyframe)
666         FileXML output;
668 // cause data to be stored directly in text
669         output.set_shared_string(keyframe->data, MESSAGESIZE);
670         output.tag.set_title("ROTATE");
671         output.tag.set_property("ANGLE", (float)config.angle);
672         output.tag.set_property("PIVOT_X", (float)config.pivot_x);
673         output.tag.set_property("PIVOT_Y", (float)config.pivot_y);
674         output.tag.set_property("DRAW_PIVOT", (int)config.draw_pivot);
675 //      output.tag.set_property("INTERPOLATE", (int)config.bilinear);
676         output.append_tag();
677         output.terminate_string();
678 // data is now in *text
681 void RotateEffect::read_data(KeyFrame *keyframe)
683         FileXML input;
685         input.set_shared_string(keyframe->data, strlen(keyframe->data));
687         int result = 0;
689         while(!result)
690         {
691                 result = input.read_tag();
693                 if(!result)
694                 {
695                         if(input.tag.title_is("ROTATE"))
696                         {
697                                 config.angle = input.tag.get_property("ANGLE", (float)config.angle);
698                                 config.pivot_x = input.tag.get_property("PIVOT_X", (float)config.pivot_x);
699                                 config.pivot_y = input.tag.get_property("PIVOT_Y", (float)config.pivot_y);
700                                 config.draw_pivot = input.tag.get_property("DRAW_PIVOT", (int)config.draw_pivot);
701 //                              config.bilinear = input.tag.get_property("INTERPOLATE", (int)config.bilinear);
702                         }
703                 }
704         }
707 int RotateEffect::process_buffer(VFrame *frame,
708         int64_t start_position,
709         double frame_rate)
711         load_configuration();
712         int w = frame->get_w();
713         int h = frame->get_h();
714 //printf("RotateEffect::process_realtime 1 %d %f\n", config.bilinear, config.angle);
717         if(config.angle == 0)
718         {
719                 read_frame(frame, 
720                         0, 
721                         start_position, 
722                         frame_rate,
723                         get_use_opengl());
724                 return 1;
725         }
727         if(!engine) engine = new AffineEngine(PluginClient::smp + 1, 
728                 PluginClient::smp + 1);
729         engine->set_pivot((int)(config.pivot_x * get_input()->get_w() / 100), 
730                 (int)(config.pivot_y * get_input()->get_h() / 100));
732         if(get_use_opengl())
733         {
734                 read_frame(frame, 
735                         0, 
736                         start_position, 
737                         frame_rate,
738                         get_use_opengl());
739                 return run_opengl();
740         }
743 // engine->set_viewport(50, 
744 // 50, 
745 // 100, 
746 // 100);
747 // engine->set_pivot(100, 100);
750         VFrame *temp_frame = PluginVClient::new_temp(get_input()->get_w(),
751                 get_input()->get_h(),
752                 get_input()->get_color_model());
753         read_frame(temp_frame, 
754                 0, 
755                 start_position, 
756                 frame_rate,
757                 get_use_opengl());
758         frame->clear_frame();
759         engine->rotate(frame, 
760                 temp_frame, 
761                 config.angle);
764 // Draw center
765 #define CENTER_H 20
766 #define CENTER_W 20
767 #define DRAW_CENTER(components, type, max) \
768 { \
769         type **rows = (type**)get_output()->get_rows(); \
770         if(center_x >= 0 && center_x < w || \
771                 center_y >= 0 && center_y < h) \
772         { \
773                 type *hrow = rows[center_y] + components * (center_x - CENTER_W / 2); \
774                 for(int i = center_x - CENTER_W / 2; i <= center_x + CENTER_W / 2; i++) \
775                 { \
776                         if(i >= 0 && i < w) \
777                         { \
778                                 hrow[0] = max - hrow[0]; \
779                                 hrow[1] = max - hrow[1]; \
780                                 hrow[2] = max - hrow[2]; \
781                                 hrow += components; \
782                         } \
783                 } \
785                 for(int i = center_y - CENTER_W / 2; i <= center_y + CENTER_W / 2; i++) \
786                 { \
787                         if(i >= 0 && i < h) \
788                         { \
789                                 type *vrow = rows[i] + center_x * components; \
790                                 vrow[0] = max - vrow[0]; \
791                                 vrow[1] = max - vrow[1]; \
792                                 vrow[2] = max - vrow[2]; \
793                         } \
794                 } \
795         } \
798         if(config.draw_pivot)
799         {
800                 int center_x = (int)(config.pivot_x * w / 100); \
801                 int center_y = (int)(config.pivot_y * h / 100); \
802                 switch(get_output()->get_color_model())
803                 {
804                         case BC_RGB_FLOAT:
805                                 DRAW_CENTER(3, float, 1.0)
806                                 break;
807                         case BC_RGBA_FLOAT:
808                                 DRAW_CENTER(4, float, 1.0)
809                                 break;
810                         case BC_RGB888:
811                                 DRAW_CENTER(3, unsigned char, 0xff)
812                                 break;
813                         case BC_RGBA8888:
814                                 DRAW_CENTER(4, unsigned char, 0xff)
815                                 break;
816                         case BC_YUV888:
817                                 DRAW_CENTER(3, unsigned char, 0xff)
818                                 break;
819                         case BC_YUVA8888:
820                                 DRAW_CENTER(4, unsigned char, 0xff)
821                                 break;
822                 }
823         }
825 // Conserve memory by deleting large frames
826         if(get_input()->get_w() > PLUGIN_MAX_W &&
827                 get_input()->get_h() > PLUGIN_MAX_H)
828         {
829                 delete engine;
830                 engine = 0;
831         }
832         return 0;
837 int RotateEffect::handle_opengl()
839 #ifdef HAVE_GL
840         engine->set_opengl(1);
841         engine->rotate(get_output(), 
842                 get_output(), 
843                 config.angle);
844         engine->set_opengl(0);
846         if(config.draw_pivot)
847         {
848                 int w = get_output()->get_w();
849                 int h = get_output()->get_h();
850                 int center_x = (int)(config.pivot_x * w / 100); \
851                 int center_y = (int)(config.pivot_y * h / 100); \
852                 
853                 glDisable(GL_TEXTURE_2D);
854                 glColor4f(1.0, 1.0, 1.0, 1.0);
855                 glLogicOp(GL_XOR);
856                 glEnable(GL_COLOR_LOGIC_OP);
857                 glBegin(GL_LINES);
858                 glVertex3f(center_x, -h + center_y - CENTER_H / 2, 0.0);
859                 glVertex3f(center_x, -h + center_y + CENTER_H / 2, 0.0);
860                 glEnd();
861                 glBegin(GL_LINES);
862                 glVertex3f(center_x - CENTER_W / 2, -h + center_y, 0.0);
863                 glVertex3f(center_x + CENTER_W / 2, -h + center_y, 0.0);
864                 glEnd();
865                 glDisable(GL_COLOR_LOGIC_OP);
866         }
867 #endif