add new cakewalk icons, add new shapewipe shapes, rework shapewipe plugin, fix 3rd...
[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.01);
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         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, 300, 230, 300, 230, 0)
267 {
268         this->plugin = plugin;
269 }
270
271 #define RADIUS 30
272
273 void RotateWindow::create_objects()
274 {
275         int x = 10, y = 10;
276         BC_Title *title;
277         add_tool(new BC_Title(x, y, _("Rotate")));
278         x += 50;  y += 20;
279         add_tool(toggle0 = new RotateToggle(this, plugin,
280                 plugin->config.angle == 0, x, y, 0, "0"));
281     x += RADIUS;  y += RADIUS;
282         add_tool(toggle90 = new RotateToggle(this, plugin,
283                 plugin->config.angle == 90, x, y, 90, "90"));
284     x -= RADIUS;  y += RADIUS;
285         add_tool(toggle180 = new RotateToggle(this, plugin,
286                 plugin->config.angle == 180, x, y, 180, "180"));
287     x -= RADIUS;  y -= RADIUS;
288         add_tool(toggle270 = new RotateToggle(this, plugin,
289                 plugin->config.angle == 270, x, y, 270, "270"));
290 //      add_subwindow(bilinear = new RotateInterpolate(plugin, 10, y + 60));
291         x += 150;  y -= 50;
292         add_tool(fine = new RotateFine(this, plugin, x, y));
293         y += fine->get_h() + 10;
294         add_tool(text = new RotateText(this, plugin, x, y));
295         y += 25;
296         add_tool(new BC_Title(x, y, _("Degrees")));
297
298         y += text->get_h() + 10;
299         add_subwindow(title = new BC_Title(x, y, _("Pivot (x,y):")));
300         y += title->get_h() + 10;
301         add_subwindow(this->x = new RotateX(this, plugin, x, y));
302         x += this->x->get_w() + 10;
303         add_subwindow(this->y = new RotateY(this, plugin, x, y));
304
305 //      y += this->y->get_h() + 10;
306         x = 10;
307         add_subwindow(draw_pivot = new RotateDrawPivot(this, plugin, x, y));
308         y += 60;
309         add_subwindow(reset = new RotateReset(plugin, this, x, y));
310
311         show_window();
312 }
313
314
315
316 int RotateWindow::update()
317 {
318         update_fine();
319         update_toggles();
320         update_text();
321 //      bilinear->update(plugin->config.bilinear);
322         return 0;
323 }
324
325 int RotateWindow::update_fine()
326 {
327         fine->update(plugin->config.angle);
328         x->update(plugin->config.pivot_x);
329         y->update(plugin->config.pivot_y);
330         return 0;
331 }
332
333 int RotateWindow::update_text()
334 {
335         text->update(plugin->config.angle);
336         return 0;
337 }
338
339 int RotateWindow::update_toggles()
340 {
341         toggle0->update(EQUIV(plugin->config.angle, 0));
342         toggle90->update(EQUIV(plugin->config.angle, 90));
343         toggle180->update(EQUIV(plugin->config.angle, 180));
344         toggle270->update(EQUIV(plugin->config.angle, 270));
345         draw_pivot->update(plugin->config.draw_pivot);
346         return 0;
347 }
348
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 RotateEffect::RotateEffect(PluginServer *server)
383  : PluginVClient(server)
384 {
385         engine = 0;
386         need_reconfigure = 1;
387
388 }
389
390 RotateEffect::~RotateEffect()
391 {
392
393         if(engine) delete engine;
394 }
395
396
397
398 const char* RotateEffect::plugin_title() { return N_("Rotate"); }
399 int RotateEffect::is_realtime() { return 1; }
400
401
402 NEW_WINDOW_MACRO(RotateEffect, RotateWindow)
403
404
405 void RotateEffect::update_gui()
406 {
407         if(thread)
408         {
409                 load_configuration();
410                 thread->window->lock_window();
411                 ((RotateWindow*)thread->window)->update();
412                 thread->window->unlock_window();
413         }
414 }
415
416 LOAD_CONFIGURATION_MACRO(RotateEffect, RotateConfig)
417
418
419
420
421 void RotateEffect::save_data(KeyFrame *keyframe)
422 {
423         FileXML output;
424
425 // cause data to be stored directly in text
426         output.set_shared_output(keyframe->xbuf);
427         output.tag.set_title("ROTATE");
428         output.tag.set_property("ANGLE", (float)config.angle);
429         output.tag.set_property("PIVOT_X", (float)config.pivot_x);
430         output.tag.set_property("PIVOT_Y", (float)config.pivot_y);
431         output.tag.set_property("DRAW_PIVOT", (int)config.draw_pivot);
432 //      output.tag.set_property("INTERPOLATE", (int)config.bilinear);
433         output.append_tag();
434         output.tag.set_title("/ROTATE");
435         output.append_tag();
436         output.append_newline();
437         output.terminate_string();
438 // data is now in *text
439 }
440
441 void RotateEffect::read_data(KeyFrame *keyframe)
442 {
443         FileXML input;
444
445         input.set_shared_input(keyframe->xbuf);
446
447         int result = 0;
448
449         while(!result)
450         {
451                 result = input.read_tag();
452
453                 if(!result)
454                 {
455                         if(input.tag.title_is("ROTATE"))
456                         {
457                                 config.angle = input.tag.get_property("ANGLE", (float)config.angle);
458                                 config.pivot_x = input.tag.get_property("PIVOT_X", (float)config.pivot_x);
459                                 config.pivot_y = input.tag.get_property("PIVOT_Y", (float)config.pivot_y);
460                                 config.draw_pivot = input.tag.get_property("DRAW_PIVOT", (int)config.draw_pivot);
461 //                              config.bilinear = input.tag.get_property("INTERPOLATE", (int)config.bilinear);
462                         }
463                 }
464         }
465 }
466
467 int RotateEffect::process_buffer(VFrame *frame,
468         int64_t start_position,
469         double frame_rate)
470 {
471         load_configuration();
472         int w = frame->get_w();
473         int h = frame->get_h();
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 #define CENTER_H 20
536 #define CENTER_W 20
537 #define DRAW_CENTER(components, type, max) \
538 { \
539         type **rows = (type**)get_output()->get_rows(); \
540         if( (center_x >= 0 && center_x < w) && (center_y >= 0 && center_y < h) ) \
541         { \
542                 for(int i = center_x - CENTER_W / 2; i <= center_x + CENTER_W / 2; i++) \
543                 { \
544                         if(i >= 0 && i < w) \
545                         { \
546                                 type *hrow = rows[center_y] + components * i; \
547                                 hrow[0] = max - hrow[0]; \
548                                 hrow[1] = max - hrow[1]; \
549                                 hrow[2] = max - hrow[2]; \
550                                 hrow += components; \
551                         } \
552                 } \
553  \
554                 for(int i = center_y - CENTER_W / 2; i <= center_y + CENTER_W / 2; i++) \
555                 { \
556                         if(i >= 0 && i < h) \
557                         { \
558                                 type *vrow = rows[i] + center_x * components; \
559                                 vrow[0] = max - vrow[0]; \
560                                 vrow[1] = max - vrow[1]; \
561                                 vrow[2] = max - vrow[2]; \
562                         } \
563                 } \
564         } \
565 }
566
567         if(config.draw_pivot)
568         {
569                 int center_x = (int)(config.pivot_x * w / 100); \
570                 int center_y = (int)(config.pivot_y * h / 100); \
571
572 //printf("RotateEffect::process_buffer %d %d %d\n", __LINE__, center_x, center_y);
573                 switch(get_output()->get_color_model())
574                 {
575                         case BC_RGB_FLOAT:
576                                 DRAW_CENTER(3, float, 1.0)
577                                 break;
578                         case BC_RGBA_FLOAT:
579                                 DRAW_CENTER(4, float, 1.0)
580                                 break;
581                         case BC_RGB888:
582                                 DRAW_CENTER(3, unsigned char, 0xff)
583                                 break;
584                         case BC_RGBA8888:
585                                 DRAW_CENTER(4, unsigned char, 0xff)
586                                 break;
587                         case BC_YUV888:
588                                 DRAW_CENTER(3, unsigned char, 0xff)
589                                 break;
590                         case BC_YUVA8888:
591                                 DRAW_CENTER(4, unsigned char, 0xff)
592                                 break;
593                 }
594         }
595
596 // Conserve memory by deleting large frames
597         if(get_input()->get_w() > PLUGIN_MAX_W &&
598                 get_input()->get_h() > PLUGIN_MAX_H)
599         {
600                 delete engine;
601                 engine = 0;
602         }
603         return 0;
604 }
605
606
607
608 int RotateEffect::handle_opengl()
609 {
610 #ifdef HAVE_GL
611         engine->set_opengl(1);
612         engine->rotate(get_output(),
613                 get_output(),
614                 config.angle);
615         engine->set_opengl(0);
616
617         if(config.draw_pivot)
618         {
619                 int w = get_output()->get_w();
620                 int h = get_output()->get_h();
621                 int center_x = (int)(config.pivot_x * w / 100);
622                 int center_y = (int)(config.pivot_y * h / 100);
623
624                 glDisable(GL_TEXTURE_2D);
625                 glColor4f(0.0, 0.0, 0.0, 1.0);
626                 glBegin(GL_LINES);
627                 glVertex3f(center_x, -h + center_y - CENTER_H / 2, 0.0);
628                 glVertex3f(center_x, -h + center_y + CENTER_H / 2, 0.0);
629                 glEnd();
630                 glBegin(GL_LINES);
631                 glVertex3f(center_x - CENTER_W / 2, -h + center_y, 0.0);
632                 glVertex3f(center_x + CENTER_W / 2, -h + center_y, 0.0);
633                 glEnd();
634                 glColor4f(1.0, 1.0, 1.0, 1.0);
635                 glBegin(GL_LINES);
636                 glVertex3f(center_x - 1, -h + center_y - CENTER_H / 2 - 1, 0.0);
637                 glVertex3f(center_x - 1, -h + center_y + CENTER_H / 2 - 1, 0.0);
638                 glEnd();
639                 glBegin(GL_LINES);
640                 glVertex3f(center_x - CENTER_W / 2 - 1, -h + center_y - 1, 0.0);
641                 glVertex3f(center_x + CENTER_W / 2 - 1, -h + center_y - 1, 0.0);
642                 glEnd();
643         }
644 #endif
645         return 0;
646 }
647
648