update internationalization data
[goodguy/history.git] / cinelerra-5.0 / plugins / rotate / rotate.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  * 
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.
10  * 
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.
15  * 
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
19  * 
20  */
21
22 #include "affine.h"
23 #include "bcdisplayinfo.h"
24 #include "clip.h"
25 #include "bchash.h"
26 #include "filexml.h"
27 #include "guicast.h"
28 #include "language.h"
29 #include "pluginvclient.h"
30 #include "rotateframe.h"
31 #include "vframe.h"
32
33
34 #include <string.h>
35
36
37
38 #define MAXANGLE 360
39
40
41 class RotateEffect;
42 class RotateWindow;
43
44
45 class RotateConfig
46 {
47 public:
48         RotateConfig();
49
50         int equivalent(RotateConfig &that);
51         void copy_from(RotateConfig &that);
52         void interpolate(RotateConfig &prev, 
53                 RotateConfig &next, 
54                 long prev_frame, 
55                 long next_frame, 
56                 long current_frame);
57
58         float angle;
59         float pivot_x;
60         float pivot_y;
61         int draw_pivot;
62 //      int bilinear;
63 };
64
65 class RotateToggle : public BC_Radial
66 {
67 public:
68         RotateToggle(RotateWindow *window, 
69                 RotateEffect *plugin, 
70                 int init_value, 
71                 int x, 
72                 int y, 
73                 int value, 
74                 const char *string);
75         int handle_event();
76
77         RotateEffect *plugin;
78     RotateWindow *window;
79     int value;
80 };
81
82 class RotateDrawPivot : public BC_CheckBox
83 {
84 public:
85         RotateDrawPivot(RotateWindow *window, 
86                 RotateEffect *plugin, 
87                 int x, 
88                 int y);
89         int handle_event();
90         RotateEffect *plugin;
91     RotateWindow *window;
92     int value;
93 };
94
95 class RotateInterpolate : public BC_CheckBox
96 {
97 public:
98         RotateInterpolate(RotateEffect *plugin, int x, int y);
99         int handle_event();
100         RotateEffect *plugin;
101 };
102
103 class RotateFine : public BC_FPot
104 {
105 public:
106         RotateFine(RotateWindow *window, 
107                 RotateEffect *plugin, 
108                 int x, 
109                 int y);
110         int handle_event();
111
112         RotateEffect *plugin;
113     RotateWindow *window;
114 };
115
116 class RotateX : public BC_FPot
117 {
118 public:
119         RotateX(RotateWindow *window, 
120                 RotateEffect *plugin, 
121                 int x, 
122                 int y);
123         int handle_event();
124         RotateEffect *plugin;
125     RotateWindow *window;
126 };
127
128 class RotateY : public BC_FPot
129 {
130 public:
131         RotateY(RotateWindow *window, 
132                 RotateEffect *plugin, 
133                 int x, 
134                 int y);
135         int handle_event();
136         RotateEffect *plugin;
137     RotateWindow *window;
138 };
139
140
141 class RotateText : public BC_TextBox
142 {
143 public:
144         RotateText(RotateWindow *window, 
145                 RotateEffect *plugin, 
146                 int x, 
147                 int y);
148         int handle_event();
149
150         RotateEffect *plugin;
151     RotateWindow *window;
152 };
153
154 class RotateWindow : public PluginClientWindow
155 {
156 public:
157         RotateWindow(RotateEffect *plugin);
158
159         void create_objects();
160
161         int update();
162         int update_fine();
163         int update_text();
164         int update_toggles();
165
166         RotateEffect *plugin;
167         RotateToggle *toggle0;
168         RotateToggle *toggle90;
169         RotateToggle *toggle180;
170         RotateToggle *toggle270;
171         RotateDrawPivot *draw_pivot;
172         RotateFine *fine;
173         RotateText *text;
174         RotateX *x;
175         RotateY *y;
176 //      RotateInterpolate *bilinear;
177 };
178
179
180
181
182 class RotateEffect : public PluginVClient
183 {
184 public:
185         RotateEffect(PluginServer *server);
186         ~RotateEffect();
187         
188         PLUGIN_CLASS_MEMBERS(RotateConfig)
189         int process_buffer(VFrame *frame,
190                 int64_t start_position,
191                 double frame_rate);
192         int is_realtime();
193         void update_gui();
194         void save_data(KeyFrame *keyframe);
195         void read_data(KeyFrame *keyframe);
196         int handle_opengl();
197
198         AffineEngine *engine;
199         int need_reconfigure;
200 };
201
202
203
204
205
206
207
208 REGISTER_PLUGIN(RotateEffect)
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227 RotateConfig::RotateConfig()
228 {
229         angle = 0;
230         pivot_x = 50;
231         pivot_y = 50;
232         draw_pivot = 0;
233 }
234
235 int RotateConfig::equivalent(RotateConfig &that)
236 {
237         return EQUIV(angle, that.angle) &&
238                 EQUIV(pivot_x, that.pivot_y) &&
239                 EQUIV(pivot_y, that.pivot_y) &&
240                 draw_pivot == that.draw_pivot;
241 }
242
243 void RotateConfig::copy_from(RotateConfig &that)
244 {
245         angle = that.angle;
246         pivot_x = that.pivot_x;
247         pivot_y = that.pivot_y;
248         draw_pivot = that.draw_pivot;
249 //      bilinear = that.bilinear;
250 }
251
252 void RotateConfig::interpolate(RotateConfig &prev, 
253                 RotateConfig &next, 
254                 long prev_frame, 
255                 long next_frame, 
256                 long current_frame)
257 {
258         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
259         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
260
261         this->angle = prev.angle * prev_scale + next.angle * next_scale;
262         this->pivot_x = prev.pivot_x * prev_scale + next.pivot_x * next_scale;
263         this->pivot_y = prev.pivot_y * prev_scale + next.pivot_y * next_scale;
264         draw_pivot = prev.draw_pivot;
265 //      bilinear = prev.bilinear;
266 }
267
268
269
270
271
272
273
274
275
276
277
278 RotateToggle::RotateToggle(RotateWindow *window, 
279         RotateEffect *plugin, 
280         int init_value, 
281         int x, 
282         int y, 
283         int value, 
284         const char *string)
285  : BC_Radial(x, y, init_value, string)
286 {
287         this->value = value;
288         this->plugin = plugin;
289     this->window = window;
290 }
291
292 int RotateToggle::handle_event()
293 {
294         plugin->config.angle = (float)value;
295     window->update();
296         plugin->send_configure_change();
297         return 1;
298 }
299
300
301
302
303
304
305
306 RotateDrawPivot::RotateDrawPivot(RotateWindow *window, 
307         RotateEffect *plugin, 
308         int x, 
309         int y)
310  : BC_CheckBox(x, y, plugin->config.draw_pivot, _("Draw pivot"))
311 {
312         this->plugin = plugin;
313     this->window = window;
314 }
315
316 int RotateDrawPivot::handle_event()
317 {
318         plugin->config.draw_pivot = get_value();
319         plugin->send_configure_change();
320         return 1;
321 }
322
323
324
325
326
327 // RotateInterpolate::RotateInterpolate(RotateEffect *plugin, int x, int y)
328 //  : BC_CheckBox(x, y, plugin->config.bilinear, _("Interpolate"))
329 // {
330 //      this->plugin = plugin;
331 // }
332 // int RotateInterpolate::handle_event()
333 // {
334 //      plugin->config.bilinear = get_value();
335 //      plugin->send_configure_change();
336 //      return 1;
337 // }
338 // 
339
340
341
342 RotateFine::RotateFine(RotateWindow *window, RotateEffect *plugin, int x, int y)
343  : BC_FPot(x, 
344         y, 
345         (float)plugin->config.angle, 
346         (float)-360, 
347         (float)360)
348 {
349         this->window = window;
350         this->plugin = plugin;
351         set_precision(0.01);
352         set_use_caption(0);
353 }
354
355 int RotateFine::handle_event()
356 {
357         plugin->config.angle = get_value();
358         window->update_toggles();
359         window->update_text();
360         plugin->send_configure_change();
361         return 1;
362 }
363
364
365
366 RotateText::RotateText(RotateWindow *window, 
367         RotateEffect *plugin, 
368         int x, 
369         int y)
370  : BC_TextBox(x, 
371         y, 
372         100,
373         1,
374         (float)plugin->config.angle)
375 {
376         this->window = window;
377         this->plugin = plugin;
378         set_precision(4);
379 }
380
381 int RotateText::handle_event()
382 {
383         plugin->config.angle = atof(get_text());
384         window->update_toggles();
385         window->update_fine();
386         plugin->send_configure_change();
387         return 1;
388 }
389
390
391
392 RotateX::RotateX(RotateWindow *window, RotateEffect *plugin, int x, int y)
393  : BC_FPot(x, 
394         y, 
395         (float)plugin->config.pivot_x, 
396         (float)0, 
397         (float)100)
398 {
399         this->window = window;
400         this->plugin = plugin;
401         set_precision(0.01);
402         set_use_caption(1);
403 }
404
405 int RotateX::handle_event()
406 {
407         plugin->config.pivot_x = get_value();
408         plugin->send_configure_change();
409         return 1;
410 }
411
412 RotateY::RotateY(RotateWindow *window, RotateEffect *plugin, int x, int y)
413  : BC_FPot(x, 
414         y, 
415         (float)plugin->config.pivot_y, 
416         (float)0, 
417         (float)100)
418 {
419         this->window = window;
420         this->plugin = plugin;
421         set_precision(0.01);
422         set_use_caption(1);
423 }
424
425 int RotateY::handle_event()
426 {
427         plugin->config.pivot_y = get_value();
428         plugin->send_configure_change();
429         return 1;
430 }
431
432
433
434
435
436
437
438
439 RotateWindow::RotateWindow(RotateEffect *plugin)
440  : PluginClientWindow(plugin,
441         250, 
442         230, 
443         250, 
444         230, 
445         0)
446 {
447         this->plugin = plugin;
448 }
449
450 #define RADIUS 30
451
452 void RotateWindow::create_objects()
453 {
454         int x = 10, y = 10;
455         BC_Title *title;
456
457
458
459         add_tool(new BC_Title(x, y, _("Rotate")));
460         x += 50;
461         y += 20;
462         add_tool(toggle0 = new RotateToggle(this, 
463                 plugin, 
464                 plugin->config.angle == 0, 
465                 x, 
466                 y, 
467                 0, 
468                 "0"));
469     x += RADIUS;
470     y += RADIUS;
471         add_tool(toggle90 = new RotateToggle(this, 
472                 plugin, 
473                 plugin->config.angle == 90, 
474                 x, 
475                 y, 
476                 90, 
477                 "90"));
478     x -= RADIUS;
479     y += RADIUS;
480         add_tool(toggle180 = new RotateToggle(this, 
481                 plugin, 
482                 plugin->config.angle == 180, 
483                 x, 
484                 y, 
485                 180, 
486                 "180"));
487     x -= RADIUS;
488     y -= RADIUS;
489         add_tool(toggle270 = new RotateToggle(this, 
490                 plugin, 
491                 plugin->config.angle == 270, 
492                 x, 
493                 y, 
494                 270, 
495                 "270"));
496 //      add_subwindow(bilinear = new RotateInterpolate(plugin, 10, y + 60));
497         x += 120;
498         y -= 50;
499         add_tool(fine = new RotateFine(this, plugin, x, y));
500         y += fine->get_h() + 10;
501         add_tool(text = new RotateText(this, plugin, x, y));
502         y += 30;
503         add_tool(new BC_Title(x, y, _("Degrees")));
504         
505
506
507
508
509         y += text->get_h() + 10;
510         add_subwindow(title = new BC_Title(x, y, _("Pivot (x,y):")));
511         y += title->get_h() + 10;
512         add_subwindow(this->x = new RotateX(this, plugin, x, y));
513         x += this->x->get_w() + 10;
514         add_subwindow(this->y = new RotateY(this, plugin, x, y));
515
516         x = 10;
517         y += this->y->get_h() + 10;
518         add_subwindow(draw_pivot = new RotateDrawPivot(this, plugin, x, y));
519
520         show_window();
521
522
523
524 }
525
526
527
528 int RotateWindow::update()
529 {
530         update_fine();
531         update_toggles();
532         update_text();
533 //      bilinear->update(plugin->config.bilinear);
534         return 0;
535 }
536
537 int RotateWindow::update_fine()
538 {
539         fine->update(plugin->config.angle);
540         x->update(plugin->config.pivot_x);
541         y->update(plugin->config.pivot_y);
542         return 0;
543 }
544
545 int RotateWindow::update_text()
546 {
547         text->update(plugin->config.angle);
548         return 0;
549 }
550
551 int RotateWindow::update_toggles()
552 {
553         toggle0->update(EQUIV(plugin->config.angle, 0));
554         toggle90->update(EQUIV(plugin->config.angle, 90));
555         toggle180->update(EQUIV(plugin->config.angle, 180));
556         toggle270->update(EQUIV(plugin->config.angle, 270));
557         draw_pivot->update(plugin->config.draw_pivot);
558         return 0;
559 }
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594 RotateEffect::RotateEffect(PluginServer *server)
595  : PluginVClient(server)
596 {
597         engine = 0;
598         need_reconfigure = 1;
599         
600 }
601
602 RotateEffect::~RotateEffect()
603 {
604         
605         if(engine) delete engine;
606 }
607
608
609
610 const char* RotateEffect::plugin_title() { return _("Rotate"); }
611 int RotateEffect::is_realtime() { return 1; }
612
613
614 NEW_WINDOW_MACRO(RotateEffect, RotateWindow)
615
616
617 void RotateEffect::update_gui()
618 {
619         if(thread)
620         {
621                 load_configuration();
622                 thread->window->lock_window();
623                 ((RotateWindow*)thread->window)->update();
624                 thread->window->unlock_window();
625         }
626 }
627
628 LOAD_CONFIGURATION_MACRO(RotateEffect, RotateConfig)
629
630
631
632
633 void RotateEffect::save_data(KeyFrame *keyframe)
634 {
635         FileXML output;
636
637 // cause data to be stored directly in text
638         output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
639         output.tag.set_title("ROTATE");
640         output.tag.set_property("ANGLE", (float)config.angle);
641         output.tag.set_property("PIVOT_X", (float)config.pivot_x);
642         output.tag.set_property("PIVOT_Y", (float)config.pivot_y);
643         output.tag.set_property("DRAW_PIVOT", (int)config.draw_pivot);
644 //      output.tag.set_property("INTERPOLATE", (int)config.bilinear);
645         output.append_tag();
646         output.terminate_string();
647 // data is now in *text
648 }
649
650 void RotateEffect::read_data(KeyFrame *keyframe)
651 {
652         FileXML input;
653
654         input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
655
656         int result = 0;
657
658         while(!result)
659         {
660                 result = input.read_tag();
661
662                 if(!result)
663                 {
664                         if(input.tag.title_is("ROTATE"))
665                         {
666                                 config.angle = input.tag.get_property("ANGLE", (float)config.angle);
667                                 config.pivot_x = input.tag.get_property("PIVOT_X", (float)config.pivot_x);
668                                 config.pivot_y = input.tag.get_property("PIVOT_Y", (float)config.pivot_y);
669                                 config.draw_pivot = input.tag.get_property("DRAW_PIVOT", (int)config.draw_pivot);
670 //                              config.bilinear = input.tag.get_property("INTERPOLATE", (int)config.bilinear);
671                         }
672                 }
673         }
674 }
675
676 int RotateEffect::process_buffer(VFrame *frame,
677         int64_t start_position,
678         double frame_rate)
679 {
680         load_configuration();
681         int w = frame->get_w();
682         int h = frame->get_h();
683 //printf("RotateEffect::process_buffer %d\n", __LINE__);
684
685
686         if(config.angle == 0)
687         {
688                 read_frame(frame, 
689                         0, 
690                         start_position, 
691                         frame_rate,
692                         get_use_opengl());
693                 return 1;
694         }
695 //printf("RotateEffect::process_buffer %d\n", __LINE__);
696
697         if(!engine) engine = new AffineEngine(PluginClient::smp + 1, 
698                 PluginClient::smp + 1);
699         int pivot_x = (int)(config.pivot_x * get_input()->get_w() / 100);
700         int pivot_y = (int)(config.pivot_y * get_input()->get_h() / 100);
701         engine->set_in_pivot(pivot_x, pivot_y);
702         engine->set_out_pivot(pivot_x, pivot_y);
703
704
705 // Test
706 // engine->set_out_viewport(0, 0, 320, 240);
707 // engine->set_out_pivot(160, 120);
708
709         if(get_use_opengl())
710         {
711                 read_frame(frame, 
712                         0, 
713                         start_position, 
714                         frame_rate,
715                         get_use_opengl());
716                 return run_opengl();
717         }
718 //printf("RotateEffect::process_buffer %d\n", __LINE__);
719
720
721 // engine->set_viewport(50, 
722 // 50, 
723 // 100, 
724 // 100);
725 // engine->set_pivot(100, 100);
726
727
728         VFrame *temp_frame = PluginVClient::new_temp(get_input()->get_w(),
729                 get_input()->get_h(),
730                 get_input()->get_color_model());
731         read_frame(temp_frame, 
732                 0, 
733                 start_position, 
734                 frame_rate,
735                 get_use_opengl());
736         frame->clear_frame();
737         engine->rotate(frame, 
738                 temp_frame, 
739                 config.angle);
740
741 //printf("RotateEffect::process_buffer %d\n", __LINE__);
742
743 // Draw center
744 #define CENTER_H 20
745 #define CENTER_W 20
746 #define DRAW_CENTER(components, type, max) \
747 { \
748         type **rows = (type**)get_output()->get_rows(); \
749         if( (center_x >= 0 && center_x < w) || (center_y >= 0 && center_y < h) ) \
750         { \
751                 type *hrow = rows[center_y] + components * (center_x - CENTER_W / 2); \
752                 for(int i = center_x - CENTER_W / 2; i <= center_x + CENTER_W / 2; i++) \
753                 { \
754                         if(i >= 0 && i < w) \
755                         { \
756                                 hrow[0] = max - hrow[0]; \
757                                 hrow[1] = max - hrow[1]; \
758                                 hrow[2] = max - hrow[2]; \
759                                 hrow += components; \
760                         } \
761                 } \
762  \
763                 for(int i = center_y - CENTER_W / 2; i <= center_y + CENTER_W / 2; i++) \
764                 { \
765                         if(i >= 0 && i < h) \
766                         { \
767                                 type *vrow = rows[i] + center_x * components; \
768                                 vrow[0] = max - vrow[0]; \
769                                 vrow[1] = max - vrow[1]; \
770                                 vrow[2] = max - vrow[2]; \
771                         } \
772                 } \
773         } \
774 }
775
776         if(config.draw_pivot)
777         {
778                 int center_x = (int)(config.pivot_x * w / 100); \
779                 int center_y = (int)(config.pivot_y * h / 100); \
780
781 //printf("RotateEffect::process_buffer %d %d %d\n", __LINE__, center_x, center_y);
782                 switch(get_output()->get_color_model())
783                 {
784                         case BC_RGB_FLOAT:
785                                 DRAW_CENTER(3, float, 1.0)
786                                 break;
787                         case BC_RGBA_FLOAT:
788                                 DRAW_CENTER(4, float, 1.0)
789                                 break;
790                         case BC_RGB888:
791                                 DRAW_CENTER(3, unsigned char, 0xff)
792                                 break;
793                         case BC_RGBA8888:
794                                 DRAW_CENTER(4, unsigned char, 0xff)
795                                 break;
796                         case BC_YUV888:
797                                 DRAW_CENTER(3, unsigned char, 0xff)
798                                 break;
799                         case BC_YUVA8888:
800                                 DRAW_CENTER(4, unsigned char, 0xff)
801                                 break;
802                 }
803         }
804
805 // Conserve memory by deleting large frames
806         if(get_input()->get_w() > PLUGIN_MAX_W &&
807                 get_input()->get_h() > PLUGIN_MAX_H)
808         {
809                 delete engine;
810                 engine = 0;
811         }
812         return 0;
813 }
814
815
816
817 int RotateEffect::handle_opengl()
818 {
819 #ifdef HAVE_GL
820         engine->set_opengl(1);
821         engine->rotate(get_output(), 
822                 get_output(), 
823                 config.angle);
824         engine->set_opengl(0);
825
826         if(config.draw_pivot)
827         {
828                 int w = get_output()->get_w();
829                 int h = get_output()->get_h();
830                 int center_x = (int)(config.pivot_x * w / 100);
831                 int center_y = (int)(config.pivot_y * h / 100);
832                 
833                 glDisable(GL_TEXTURE_2D);
834                 glColor4f(0.0, 0.0, 0.0, 1.0);
835                 glBegin(GL_LINES);
836                 glVertex3f(center_x, -h + center_y - CENTER_H / 2, 0.0);
837                 glVertex3f(center_x, -h + center_y + CENTER_H / 2, 0.0);
838                 glEnd();
839                 glBegin(GL_LINES);
840                 glVertex3f(center_x - CENTER_W / 2, -h + center_y, 0.0);
841                 glVertex3f(center_x + CENTER_W / 2, -h + center_y, 0.0);
842                 glEnd();
843                 glColor4f(1.0, 1.0, 1.0, 1.0);
844                 glBegin(GL_LINES);
845                 glVertex3f(center_x - 1, -h + center_y - CENTER_H / 2 - 1, 0.0);
846                 glVertex3f(center_x - 1, -h + center_y + CENTER_H / 2 - 1, 0.0);
847                 glEnd();
848                 glBegin(GL_LINES);
849                 glVertex3f(center_x - CENTER_W / 2 - 1, -h + center_y - 1, 0.0);
850                 glVertex3f(center_x + CENTER_W / 2 - 1, -h + center_y - 1, 0.0);
851                 glEnd();
852         }
853 #endif
854         return 0;
855 }
856
857