fix trace locks hang, drag handle rework-again, 12 reset btns on plugins, booby on
[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,
267         250,
268         230,
269         250,
270         230,
271         0)
272 {
273         this->plugin = plugin;
274 }
275
276 #define RADIUS 30
277
278 void RotateWindow::create_objects()
279 {
280         int x = 10, y = 10;
281         BC_Title *title;
282
283
284
285         add_tool(new BC_Title(x, y, _("Rotate")));
286         x += 50;
287         y += 20;
288         add_tool(toggle0 = new RotateToggle(this,
289                 plugin,
290                 plugin->config.angle == 0,
291                 x,
292                 y,
293                 0,
294                 "0"));
295     x += RADIUS;
296     y += RADIUS;
297         add_tool(toggle90 = new RotateToggle(this,
298                 plugin,
299                 plugin->config.angle == 90,
300                 x,
301                 y,
302                 90,
303                 "90"));
304     x -= RADIUS;
305     y += RADIUS;
306         add_tool(toggle180 = new RotateToggle(this,
307                 plugin,
308                 plugin->config.angle == 180,
309                 x,
310                 y,
311                 180,
312                 "180"));
313     x -= RADIUS;
314     y -= RADIUS;
315         add_tool(toggle270 = new RotateToggle(this,
316                 plugin,
317                 plugin->config.angle == 270,
318                 x,
319                 y,
320                 270,
321                 "270"));
322 //      add_subwindow(bilinear = new RotateInterpolate(plugin, 10, y + 60));
323         x += 120;
324         y -= 50;
325         add_tool(fine = new RotateFine(this, plugin, x, y));
326         y += fine->get_h() + 10;
327         add_tool(text = new RotateText(this, plugin, x, y));
328         y += 25;
329         add_tool(new BC_Title(x, y, _("Degrees")));
330
331
332
333
334
335         y += text->get_h() + 10;
336         add_subwindow(title = new BC_Title(x, y, _("Pivot (x,y):")));
337         y += title->get_h() + 10;
338         add_subwindow(this->x = new RotateX(this, plugin, x, y));
339         x += this->x->get_w() + 10;
340         add_subwindow(this->y = new RotateY(this, plugin, x, y));
341
342 //      y += this->y->get_h() + 10;
343         x = 10;
344         add_subwindow(draw_pivot = new RotateDrawPivot(this, plugin, x, y));
345         y += 60;
346         add_subwindow(reset = new RotateReset(plugin, this, x, y));
347
348         show_window();
349 }
350
351
352
353 int RotateWindow::update()
354 {
355         update_fine();
356         update_toggles();
357         update_text();
358 //      bilinear->update(plugin->config.bilinear);
359         return 0;
360 }
361
362 int RotateWindow::update_fine()
363 {
364         fine->update(plugin->config.angle);
365         x->update(plugin->config.pivot_x);
366         y->update(plugin->config.pivot_y);
367         return 0;
368 }
369
370 int RotateWindow::update_text()
371 {
372         text->update(plugin->config.angle);
373         return 0;
374 }
375
376 int RotateWindow::update_toggles()
377 {
378         toggle0->update(EQUIV(plugin->config.angle, 0));
379         toggle90->update(EQUIV(plugin->config.angle, 90));
380         toggle180->update(EQUIV(plugin->config.angle, 180));
381         toggle270->update(EQUIV(plugin->config.angle, 270));
382         draw_pivot->update(plugin->config.draw_pivot);
383         return 0;
384 }
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419 RotateEffect::RotateEffect(PluginServer *server)
420  : PluginVClient(server)
421 {
422         engine = 0;
423         need_reconfigure = 1;
424
425 }
426
427 RotateEffect::~RotateEffect()
428 {
429
430         if(engine) delete engine;
431 }
432
433
434
435 const char* RotateEffect::plugin_title() { return N_("Rotate"); }
436 int RotateEffect::is_realtime() { return 1; }
437
438
439 NEW_WINDOW_MACRO(RotateEffect, RotateWindow)
440
441
442 void RotateEffect::update_gui()
443 {
444         if(thread)
445         {
446                 load_configuration();
447                 thread->window->lock_window();
448                 ((RotateWindow*)thread->window)->update();
449                 thread->window->unlock_window();
450         }
451 }
452
453 LOAD_CONFIGURATION_MACRO(RotateEffect, RotateConfig)
454
455
456
457
458 void RotateEffect::save_data(KeyFrame *keyframe)
459 {
460         FileXML output;
461
462 // cause data to be stored directly in text
463         output.set_shared_output(keyframe->xbuf);
464         output.tag.set_title("ROTATE");
465         output.tag.set_property("ANGLE", (float)config.angle);
466         output.tag.set_property("PIVOT_X", (float)config.pivot_x);
467         output.tag.set_property("PIVOT_Y", (float)config.pivot_y);
468         output.tag.set_property("DRAW_PIVOT", (int)config.draw_pivot);
469 //      output.tag.set_property("INTERPOLATE", (int)config.bilinear);
470         output.append_tag();
471         output.tag.set_title("/ROTATE");
472         output.append_tag();
473         output.append_newline();
474         output.terminate_string();
475 // data is now in *text
476 }
477
478 void RotateEffect::read_data(KeyFrame *keyframe)
479 {
480         FileXML input;
481
482         input.set_shared_input(keyframe->xbuf);
483
484         int result = 0;
485
486         while(!result)
487         {
488                 result = input.read_tag();
489
490                 if(!result)
491                 {
492                         if(input.tag.title_is("ROTATE"))
493                         {
494                                 config.angle = input.tag.get_property("ANGLE", (float)config.angle);
495                                 config.pivot_x = input.tag.get_property("PIVOT_X", (float)config.pivot_x);
496                                 config.pivot_y = input.tag.get_property("PIVOT_Y", (float)config.pivot_y);
497                                 config.draw_pivot = input.tag.get_property("DRAW_PIVOT", (int)config.draw_pivot);
498 //                              config.bilinear = input.tag.get_property("INTERPOLATE", (int)config.bilinear);
499                         }
500                 }
501         }
502 }
503
504 int RotateEffect::process_buffer(VFrame *frame,
505         int64_t start_position,
506         double frame_rate)
507 {
508         load_configuration();
509         int w = frame->get_w();
510         int h = frame->get_h();
511 //printf("RotateEffect::process_buffer %d\n", __LINE__);
512
513
514         if(config.angle == 0)
515         {
516                 read_frame(frame,
517                         0,
518                         start_position,
519                         frame_rate,
520                         get_use_opengl());
521                 return 1;
522         }
523 //printf("RotateEffect::process_buffer %d\n", __LINE__);
524
525         if(!engine) engine = new AffineEngine(PluginClient::smp + 1,
526                 PluginClient::smp + 1);
527         int pivot_x = (int)(config.pivot_x * get_input()->get_w() / 100);
528         int pivot_y = (int)(config.pivot_y * get_input()->get_h() / 100);
529         engine->set_in_pivot(pivot_x, pivot_y);
530         engine->set_out_pivot(pivot_x, pivot_y);
531
532
533 // Test
534 // engine->set_out_viewport(0, 0, 320, 240);
535 // engine->set_out_pivot(160, 120);
536
537         if(get_use_opengl())
538         {
539                 read_frame(frame,
540                         0,
541                         start_position,
542                         frame_rate,
543                         get_use_opengl());
544                 return run_opengl();
545         }
546 //printf("RotateEffect::process_buffer %d\n", __LINE__);
547
548
549 // engine->set_viewport(50,
550 // 50,
551 // 100,
552 // 100);
553 // engine->set_pivot(100, 100);
554
555
556         VFrame *temp_frame = PluginVClient::new_temp(get_input()->get_w(),
557                 get_input()->get_h(),
558                 get_input()->get_color_model());
559         read_frame(temp_frame,
560                 0,
561                 start_position,
562                 frame_rate,
563                 get_use_opengl());
564         frame->clear_frame();
565         engine->rotate(frame,
566                 temp_frame,
567                 config.angle);
568
569 //printf("RotateEffect::process_buffer %d draw_pivot=%d\n", __LINE__, config.draw_pivot);
570
571 // Draw center
572 #define CENTER_H 20
573 #define CENTER_W 20
574 #define DRAW_CENTER(components, type, max) \
575 { \
576         type **rows = (type**)get_output()->get_rows(); \
577         if( (center_x >= 0 && center_x < w) || (center_y >= 0 && center_y < h) ) \
578         { \
579                 type *hrow = rows[center_y] + components * (center_x - CENTER_W / 2); \
580                 for(int i = center_x - CENTER_W / 2; i <= center_x + CENTER_W / 2; i++) \
581                 { \
582                         if(i >= 0 && i < w) \
583                         { \
584                                 hrow[0] = max - hrow[0]; \
585                                 hrow[1] = max - hrow[1]; \
586                                 hrow[2] = max - hrow[2]; \
587                                 hrow += components; \
588                         } \
589                 } \
590  \
591                 for(int i = center_y - CENTER_W / 2; i <= center_y + CENTER_W / 2; i++) \
592                 { \
593                         if(i >= 0 && i < h) \
594                         { \
595                                 type *vrow = rows[i] + center_x * components; \
596                                 vrow[0] = max - vrow[0]; \
597                                 vrow[1] = max - vrow[1]; \
598                                 vrow[2] = max - vrow[2]; \
599                         } \
600                 } \
601         } \
602 }
603
604         if(config.draw_pivot)
605         {
606                 int center_x = (int)(config.pivot_x * w / 100); \
607                 int center_y = (int)(config.pivot_y * h / 100); \
608
609 //printf("RotateEffect::process_buffer %d %d %d\n", __LINE__, center_x, center_y);
610                 switch(get_output()->get_color_model())
611                 {
612                         case BC_RGB_FLOAT:
613                                 DRAW_CENTER(3, float, 1.0)
614                                 break;
615                         case BC_RGBA_FLOAT:
616                                 DRAW_CENTER(4, float, 1.0)
617                                 break;
618                         case BC_RGB888:
619                                 DRAW_CENTER(3, unsigned char, 0xff)
620                                 break;
621                         case BC_RGBA8888:
622                                 DRAW_CENTER(4, unsigned char, 0xff)
623                                 break;
624                         case BC_YUV888:
625                                 DRAW_CENTER(3, unsigned char, 0xff)
626                                 break;
627                         case BC_YUVA8888:
628                                 DRAW_CENTER(4, unsigned char, 0xff)
629                                 break;
630                 }
631         }
632
633 // Conserve memory by deleting large frames
634         if(get_input()->get_w() > PLUGIN_MAX_W &&
635                 get_input()->get_h() > PLUGIN_MAX_H)
636         {
637                 delete engine;
638                 engine = 0;
639         }
640         return 0;
641 }
642
643
644
645 int RotateEffect::handle_opengl()
646 {
647 #ifdef HAVE_GL
648         engine->set_opengl(1);
649         engine->rotate(get_output(),
650                 get_output(),
651                 config.angle);
652         engine->set_opengl(0);
653
654         if(config.draw_pivot)
655         {
656                 int w = get_output()->get_w();
657                 int h = get_output()->get_h();
658                 int center_x = (int)(config.pivot_x * w / 100);
659                 int center_y = (int)(config.pivot_y * h / 100);
660
661                 glDisable(GL_TEXTURE_2D);
662                 glColor4f(0.0, 0.0, 0.0, 1.0);
663                 glBegin(GL_LINES);
664                 glVertex3f(center_x, -h + center_y - CENTER_H / 2, 0.0);
665                 glVertex3f(center_x, -h + center_y + CENTER_H / 2, 0.0);
666                 glEnd();
667                 glBegin(GL_LINES);
668                 glVertex3f(center_x - CENTER_W / 2, -h + center_y, 0.0);
669                 glVertex3f(center_x + CENTER_W / 2, -h + center_y, 0.0);
670                 glEnd();
671                 glColor4f(1.0, 1.0, 1.0, 1.0);
672                 glBegin(GL_LINES);
673                 glVertex3f(center_x - 1, -h + center_y - CENTER_H / 2 - 1, 0.0);
674                 glVertex3f(center_x - 1, -h + center_y + CENTER_H / 2 - 1, 0.0);
675                 glEnd();
676                 glBegin(GL_LINES);
677                 glVertex3f(center_x - CENTER_W / 2 - 1, -h + center_y - 1, 0.0);
678                 glVertex3f(center_x + CENTER_W / 2 - 1, -h + center_y - 1, 0.0);
679                 glEnd();
680         }
681 #endif
682         return 0;
683 }
684
685