tweak fr.po folder names, rotate plugin fixes
[goodguy/cinelerra.git] / cinelerra-5.1 / 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
23 #include "rotate.h"
24
25 #define MAXANGLE 360
26
27 REGISTER_PLUGIN(RotateEffect)
28
29
30
31
32 RotateConfig::RotateConfig()
33 {
34         reset();
35 }
36
37 void RotateConfig::reset()
38 {
39         angle = 0.0;
40         pivot_x = 50.0;
41         pivot_y = 50.0;
42         draw_pivot = 0;
43 }
44
45 int RotateConfig::equivalent(RotateConfig &that)
46 {
47         return EQUIV(angle, that.angle) &&
48                 EQUIV(pivot_x, that.pivot_y) &&
49                 EQUIV(pivot_y, that.pivot_y) &&
50                 draw_pivot == that.draw_pivot;
51 }
52
53 void RotateConfig::copy_from(RotateConfig &that)
54 {
55         angle = that.angle;
56         pivot_x = that.pivot_x;
57         pivot_y = that.pivot_y;
58         draw_pivot = that.draw_pivot;
59 //      bilinear = that.bilinear;
60 }
61
62 void RotateConfig::interpolate(RotateConfig &prev,
63                 RotateConfig &next,
64                 long prev_frame,
65                 long next_frame,
66                 long current_frame)
67 {
68         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
69         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
70
71         this->angle = prev.angle * prev_scale + next.angle * next_scale;
72         this->pivot_x = prev.pivot_x * prev_scale + next.pivot_x * next_scale;
73         this->pivot_y = prev.pivot_y * prev_scale + next.pivot_y * next_scale;
74         draw_pivot = prev.draw_pivot;
75 //      bilinear = prev.bilinear;
76 }
77
78
79
80
81
82
83
84
85
86
87
88 RotateToggle::RotateToggle(RotateWindow *window,
89         RotateEffect *plugin,
90         int init_value,
91         int x,
92         int y,
93         int value,
94         const char *string)
95  : BC_Radial(x, y, init_value, string)
96 {
97         this->value = value;
98         this->plugin = plugin;
99         this->window = window;
100 }
101
102 int RotateToggle::handle_event()
103 {
104         plugin->config.angle = (float)value;
105         window->update();
106         plugin->send_configure_change();
107         return 1;
108 }
109
110
111
112
113
114
115
116 RotateDrawPivot::RotateDrawPivot(RotateWindow *window,
117         RotateEffect *plugin,
118         int x,
119         int y)
120  : BC_CheckBox(x, y, plugin->config.draw_pivot, _("Draw pivot"))
121 {
122         this->plugin = plugin;
123         this->window = window;
124 }
125
126 int RotateDrawPivot::handle_event()
127 {
128         plugin->config.draw_pivot = get_value();
129         plugin->send_configure_change();
130         return 1;
131 }
132
133
134
135
136
137 // RotateInterpolate::RotateInterpolate(RotateEffect *plugin, int x, int y)
138 //  : BC_CheckBox(x, y, plugin->config.bilinear, _("Interpolate"))
139 // {
140 //      this->plugin = plugin;
141 // }
142 // int RotateInterpolate::handle_event()
143 // {
144 //      plugin->config.bilinear = get_value();
145 //      plugin->send_configure_change();
146 //      return 1;
147 // }
148 //
149
150
151
152 RotateFine::RotateFine(RotateWindow *window, RotateEffect *plugin, int x, int y)
153  : BC_FPot(x,
154         y,
155         (float)plugin->config.angle,
156         (float)-360,
157         (float)360)
158 {
159         this->window = window;
160         this->plugin = plugin;
161         set_precision(0.1);
162         set_use_caption(0);
163 }
164
165 int RotateFine::handle_event()
166 {
167         plugin->config.angle = get_value();
168         window->update_toggles();
169         window->update_text();
170         plugin->send_configure_change();
171         return 1;
172 }
173
174
175
176 RotateText::RotateText(RotateWindow *window,
177         RotateEffect *plugin,
178         int x,
179         int y)
180  : BC_TextBox(x,
181         y,
182         xS(90),
183         1,
184         (float)plugin->config.angle)
185 {
186         this->window = window;
187         this->plugin = plugin;
188         set_precision(4);
189 }
190
191 int RotateText::handle_event()
192 {
193         plugin->config.angle = atof(get_text());
194         window->update_toggles();
195         window->update_fine();
196         plugin->send_configure_change();
197         return 1;
198 }
199
200
201
202 RotateX::RotateX(RotateWindow *window, RotateEffect *plugin, int x, int y)
203  : BC_FPot(x,
204         y,
205         (float)plugin->config.pivot_x,
206         (float)0,
207         (float)100)
208 {
209         this->window = window;
210         this->plugin = plugin;
211         set_precision(0.01);
212         set_use_caption(1);
213 }
214
215 int RotateX::handle_event()
216 {
217         plugin->config.pivot_x = get_value();
218         plugin->send_configure_change();
219         return 1;
220 }
221
222 RotateY::RotateY(RotateWindow *window, RotateEffect *plugin, int x, int y)
223  : BC_FPot(x,
224         y,
225         (float)plugin->config.pivot_y,
226         (float)0,
227         (float)100)
228 {
229         this->window = window;
230         this->plugin = plugin;
231         set_precision(0.01);
232         set_use_caption(1);
233 }
234
235 int RotateY::handle_event()
236 {
237         plugin->config.pivot_y = get_value();
238         plugin->send_configure_change();
239         return 1;
240 }
241
242
243 RotateReset::RotateReset(RotateEffect *plugin, RotateWindow *window, int x, int y)
244  : BC_GenericButton(x, y, _("Reset"))
245 {
246         this->plugin = plugin;
247         this->window = window;
248 }
249 RotateReset::~RotateReset()
250 {
251 }
252 int RotateReset::handle_event()
253 {
254         plugin->config.reset();
255         window->update();
256         plugin->send_configure_change();
257         return 1;
258 }
259
260
261
262
263
264
265 RotateWindow::RotateWindow(RotateEffect *plugin)
266  : PluginClientWindow(plugin, xS(300), yS(230), xS(300), yS(230), 0)
267 {
268         this->plugin = plugin;
269 }
270
271 #define RADIUS xS(30)
272
273 void RotateWindow::create_objects()
274 {
275         int xs10 = xS(10), xs50 = xS(50), xs150 = xS(150);
276         int ys10 = yS(10), ys20 = yS(20), ys25 = yS(25), ys50 = yS(50), ys60 = yS(60);
277         int x = xs10, y = ys10;
278         BC_Title *title;
279         add_tool(new BC_Title(x, y, _("Rotate")));
280         x += xs50;  y += ys20;
281         add_tool(toggle0 = new RotateToggle(this, plugin,
282                 plugin->config.angle == 0, x, y, 0, "0"));
283     x += RADIUS;  y += RADIUS;
284         add_tool(toggle90 = new RotateToggle(this, plugin,
285                 plugin->config.angle == 90, x, y, 90, "90"));
286     x -= RADIUS;  y += RADIUS;
287         add_tool(toggle180 = new RotateToggle(this, plugin,
288                 plugin->config.angle == 180, x, y, 180, "180"));
289     x -= RADIUS;  y -= RADIUS;
290         add_tool(toggle270 = new RotateToggle(this, plugin,
291                 plugin->config.angle == 270, x, y, 270, "270"));
292 //      add_subwindow(bilinear = new RotateInterpolate(plugin, xs10, y + ys60));
293         x += xs150;  y -= ys50;
294         add_tool(fine = new RotateFine(this, plugin, x, y));
295         y += fine->get_h() + ys10;
296         add_tool(text = new RotateText(this, plugin, x, y));
297         y += ys25;
298         add_tool(new BC_Title(x, y, _("Degrees")));
299
300         y += text->get_h() + ys10;
301         add_subwindow(title = new BC_Title(x, y, _("Pivot (x,y):")));
302         y += title->get_h() + ys10;
303         add_subwindow(this->x = new RotateX(this, plugin, x, y));
304         x += this->x->get_w() + xs10;
305         add_subwindow(this->y = new RotateY(this, plugin, x, y));
306
307 //      y += this->y->get_h() + ys10;
308         x = xs10;
309         add_subwindow(draw_pivot = new RotateDrawPivot(this, plugin, x, y));
310         y += ys60;
311         add_subwindow(reset = new RotateReset(plugin, this, x, y));
312
313         show_window();
314 }
315
316
317
318 int RotateWindow::update()
319 {
320         update_fine();
321         update_toggles();
322         update_text();
323 //      bilinear->update(plugin->config.bilinear);
324         return 0;
325 }
326
327 int RotateWindow::update_fine()
328 {
329         fine->update(plugin->config.angle);
330         x->update(plugin->config.pivot_x);
331         y->update(plugin->config.pivot_y);
332         return 0;
333 }
334
335 int RotateWindow::update_text()
336 {
337         text->update(plugin->config.angle);
338         return 0;
339 }
340
341 int RotateWindow::update_toggles()
342 {
343         toggle0->update(EQUIV(plugin->config.angle, 0));
344         toggle90->update(EQUIV(plugin->config.angle, 90));
345         toggle180->update(EQUIV(plugin->config.angle, 180));
346         toggle270->update(EQUIV(plugin->config.angle, 270));
347         draw_pivot->update(plugin->config.draw_pivot);
348         return 0;
349 }
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384 RotateEffect::RotateEffect(PluginServer *server)
385  : PluginVClient(server)
386 {
387         engine = 0;
388         need_reconfigure = 1;
389
390 }
391
392 RotateEffect::~RotateEffect()
393 {
394
395         if(engine) delete engine;
396 }
397
398
399
400 const char* RotateEffect::plugin_title() { return N_("Rotate"); }
401 int RotateEffect::is_realtime() { return 1; }
402
403
404 NEW_WINDOW_MACRO(RotateEffect, RotateWindow)
405
406
407 void RotateEffect::update_gui()
408 {
409         if(thread)
410         {
411                 load_configuration();
412                 thread->window->lock_window();
413                 ((RotateWindow*)thread->window)->update();
414                 thread->window->unlock_window();
415         }
416 }
417
418 LOAD_CONFIGURATION_MACRO(RotateEffect, RotateConfig)
419
420
421
422
423 void RotateEffect::save_data(KeyFrame *keyframe)
424 {
425         FileXML output;
426
427 // cause data to be stored directly in text
428         output.set_shared_output(keyframe->xbuf);
429         output.tag.set_title("ROTATE");
430         output.tag.set_property("ANGLE", (float)config.angle);
431         output.tag.set_property("PIVOT_X", (float)config.pivot_x);
432         output.tag.set_property("PIVOT_Y", (float)config.pivot_y);
433         output.tag.set_property("DRAW_PIVOT", (int)config.draw_pivot);
434 //      output.tag.set_property("INTERPOLATE", (int)config.bilinear);
435         output.append_tag();
436         output.tag.set_title("/ROTATE");
437         output.append_tag();
438         output.append_newline();
439         output.terminate_string();
440 // data is now in *text
441 }
442
443 void RotateEffect::read_data(KeyFrame *keyframe)
444 {
445         FileXML input;
446
447         input.set_shared_input(keyframe->xbuf);
448
449         int result = 0;
450
451         while(!result)
452         {
453                 result = input.read_tag();
454
455                 if(!result)
456                 {
457                         if(input.tag.title_is("ROTATE"))
458                         {
459                                 config.angle = input.tag.get_property("ANGLE", (float)config.angle);
460                                 config.pivot_x = input.tag.get_property("PIVOT_X", (float)config.pivot_x);
461                                 config.pivot_y = input.tag.get_property("PIVOT_Y", (float)config.pivot_y);
462                                 config.draw_pivot = input.tag.get_property("DRAW_PIVOT", (int)config.draw_pivot);
463 //                              config.bilinear = input.tag.get_property("INTERPOLATE", (int)config.bilinear);
464                         }
465                 }
466         }
467 }
468
469 int RotateEffect::process_buffer(VFrame *frame,
470         int64_t start_position,
471         double frame_rate)
472 {
473         load_configuration();
474 //printf("RotateEffect::process_buffer %d\n", __LINE__);
475
476
477         if(config.angle == 0 && !config.draw_pivot)
478         {
479                 read_frame(frame,
480                         0,
481                         start_position,
482                         frame_rate,
483                         get_use_opengl());
484                 return 1;
485         }
486 //printf("RotateEffect::process_buffer %d\n", __LINE__);
487
488         if(!engine) engine = new AffineEngine(PluginClient::smp + 1,
489                 PluginClient::smp + 1);
490         int pivot_x = (int)(config.pivot_x * get_input()->get_w() / 100);
491         int pivot_y = (int)(config.pivot_y * get_input()->get_h() / 100);
492         engine->set_in_pivot(pivot_x, pivot_y);
493         engine->set_out_pivot(pivot_x, pivot_y);
494
495
496 // Test
497 // engine->set_out_viewport(0, 0, 320, 240);
498 // engine->set_out_pivot(160, 120);
499
500         if(get_use_opengl())
501         {
502                 read_frame(frame,
503                         0,
504                         start_position,
505                         frame_rate,
506                         get_use_opengl());
507                 return run_opengl();
508         }
509 //printf("RotateEffect::process_buffer %d\n", __LINE__);
510
511
512 // engine->set_viewport(50,
513 // 50,
514 // 100,
515 // 100);
516 // engine->set_pivot(100, 100);
517
518
519         VFrame *temp_frame = PluginVClient::new_temp(get_input()->get_w(),
520                 get_input()->get_h(),
521                 get_input()->get_color_model());
522         read_frame(temp_frame,
523                 0,
524                 start_position,
525                 frame_rate,
526                 get_use_opengl());
527         frame->clear_frame();
528         engine->rotate(frame,
529                 temp_frame,
530                 config.angle);
531
532 //printf("RotateEffect::process_buffer %d draw_pivot=%d\n", __LINE__, config.draw_pivot);
533
534 // Draw center
535         if(config.draw_pivot) {
536                 VFrame *vframe = get_output();
537                 int w = vframe->get_w(), h = vframe->get_h();
538                 int mx = w > h ? w : h;
539                 int lw = mx/400 + 1, cxy = mx/80;
540                 int center_x = (int)(config.pivot_x * w/100);
541                 int center_y = (int)(config.pivot_y * h/100);
542                 int x1 = center_x - cxy, x2 = center_x + cxy;
543                 int y1 = center_y - cxy, y2 = center_y + cxy;
544                 vframe->set_pixel_color(WHITE);
545                 for( int i=0; i<lw; ++i )
546                         frame->draw_line(x1-i,center_y-i, x2-i,center_y-i);
547                 vframe->set_pixel_color(BLACK);
548                 for( int i=1; i<=lw; ++i )
549                         frame->draw_line(x1+i,center_y+i, x2+i,center_y+i);
550                 vframe->set_pixel_color(WHITE);
551                 for( int i=0; i<lw; ++i )
552                         frame->draw_line(center_x-i,y1-i, center_x-i,y2-i);
553                 vframe->set_pixel_color(BLACK);
554                 for( int i=1; i<=lw; ++i )
555                         frame->draw_line(center_x+i,y1+i, center_x+i,y2+i);
556         }
557
558 // Conserve memory by deleting large frames
559         if(get_input()->get_w() > PLUGIN_MAX_W &&
560                 get_input()->get_h() > PLUGIN_MAX_H)
561         {
562                 delete engine;
563                 engine = 0;
564         }
565         return 0;
566 }
567
568
569
570 int RotateEffect::handle_opengl()
571 {
572 #ifdef HAVE_GL
573         engine->set_opengl(1);
574         engine->rotate(get_output(),
575                 get_output(),
576                 config.angle);
577         engine->set_opengl(0);
578
579         if(config.draw_pivot)
580         {
581                 VFrame *vframe = get_output();
582                 int w = vframe->get_w(), h = vframe->get_h();
583                 int mx = w > h ? w : h;
584                 int lw = mx/400 + 1, cxy = mx/80;
585                 int center_x = (int)(config.pivot_x * w/100);
586                 int center_y = (int)(config.pivot_y * h/100);
587                 int x1 = center_x - cxy, x2 = center_x + cxy;
588                 int y1 = center_y - cxy, y2 = center_y + cxy;
589                 glDisable(GL_TEXTURE_2D);
590                 int is_yuv = BC_CModels::is_yuv(vframe->get_color_model());
591                 float rwt = 1, gwt = is_yuv? 0.5 : 1, bwt = is_yuv? 0.5 : 1;
592                 float rbk = 0, gbk = is_yuv? 0.5 : 0, bbk = is_yuv? 0.5 : 0;
593                 glBegin(GL_LINES);
594                 glColor4f(rwt, gwt, bwt, 1.0);
595                 for( int i=0; i<lw; ++i ) {
596                         glVertex3f(x1-i, center_y-i - h, 0.0);
597                         glVertex3f(x2-i, center_y-i - h, 0.0);
598                 }
599                 glColor4f(rbk, gbk, bbk, 1.0);
600                 for( int i=1; i<=lw; ++i ) {
601                         glVertex3f(x1+i, center_y+i - h, 0.0);
602                         glVertex3f(x2+i, center_y+i - h, 0.0);
603                 }
604                 glEnd();
605                 glBegin(GL_LINES);
606                 glColor4f(rwt, gwt, bwt, 1.0);
607                 for( int i=0; i<lw; ++i ) {
608                         glVertex3f(center_x-i, y1-i - h, 0.0);
609                         glVertex3f(center_x-i, y2-i - h, 0.0);
610                 }
611                 glColor4f(rbk, gbk, bbk, 1.0);
612                 for( int i=1; i<=lw; ++i ) {
613                         glVertex3f(center_x+i, y1+i - h, 0.0);
614                         glVertex3f(center_x+i, y2+i - h, 0.0);
615                 }
616                 glEnd();
617         }
618 #endif
619         return 0;
620 }
621
622