labels follow edits fix, group only ungrouped edits, add reset to 7 plugins, add...
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / polar / polar.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 "bcdisplayinfo.h"
23 #include "clip.h"
24 #include "bchash.h"
25 #include "filexml.h"
26 #include "guicast.h"
27 #include "keyframe.h"
28 #include "language.h"
29 #include "loadbalance.h"
30 #include "pluginvclient.h"
31 #include "vframe.h"
32
33
34
35 #include <string.h>
36 #include <stdint.h>
37
38
39 #define WITHIN(a, b, c) ((((a) <= (b)) && ((b) <= (c))) ? 1 : 0)
40
41
42 class PolarEffect;
43 class PolarEngine;
44 class PolarWindow;
45 class PolarReset;
46
47
48 class PolarConfig
49 {
50 public:
51         PolarConfig();
52
53         void reset();
54         void copy_from(PolarConfig &src);
55         int equivalent(PolarConfig &src);
56         void interpolate(PolarConfig &prev,
57                 PolarConfig &next,
58                 long prev_frame,
59                 long next_frame,
60                 long current_frame);
61
62         int polar_to_rectangular;
63         float depth;
64         float angle;
65         int backwards;
66         int invert;
67 };
68
69
70
71 class PolarDepth : public BC_FSlider
72 {
73 public:
74         PolarDepth(PolarEffect *plugin, int x, int y);
75         int handle_event();
76         PolarEffect *plugin;
77 };
78
79 class PolarAngle : public BC_FSlider
80 {
81 public:
82         PolarAngle(PolarEffect *plugin, int x, int y);
83         int handle_event();
84         PolarEffect *plugin;
85 };
86
87 class PolarReset : public BC_GenericButton
88 {
89 public:
90         PolarReset(PolarEffect *plugin, PolarWindow *window, int x, int y);
91         ~PolarReset();
92         int handle_event();
93         PolarEffect *plugin;
94         PolarWindow *window;
95 };
96
97 class PolarWindow : public PluginClientWindow
98 {
99 public:
100         PolarWindow(PolarEffect *plugin);
101         void create_objects();
102         void update();
103         PolarEffect *plugin;
104         PolarDepth *depth;
105         PolarAngle *angle;
106         PolarReset *reset;
107 };
108
109
110
111
112
113 class PolarPackage : public LoadPackage
114 {
115 public:
116         PolarPackage();
117         int row1, row2;
118 };
119
120 class PolarUnit : public LoadClient
121 {
122 public:
123         PolarUnit(PolarEffect *plugin, PolarEngine *server);
124         void process_package(LoadPackage *package);
125         PolarEffect *plugin;
126 };
127
128 class PolarEngine : public LoadServer
129 {
130 public:
131         PolarEngine(PolarEffect *plugin, int cpus);
132         void init_packages();
133         LoadClient* new_client();
134         LoadPackage* new_package();
135         PolarEffect *plugin;
136 };
137
138 class PolarEffect : public PluginVClient
139 {
140 public:
141         PolarEffect(PluginServer *server);
142         ~PolarEffect();
143
144         PLUGIN_CLASS_MEMBERS(PolarConfig)
145         int process_realtime(VFrame *input, VFrame *output);
146         int is_realtime();
147         void save_data(KeyFrame *keyframe);
148         void read_data(KeyFrame *keyframe);
149         void update_gui();
150
151         PolarEngine *engine;
152         VFrame *temp_frame;
153         VFrame *input, *output;
154         int need_reconfigure;
155 };
156
157
158
159 REGISTER_PLUGIN(PolarEffect)
160
161
162
163 PolarConfig::PolarConfig()
164 {
165         reset();
166 }
167
168 void PolarConfig::reset()
169 {
170         angle = 1.0;    // 0.0;
171         depth = 1.0;    // 0.0;
172         backwards = 0;
173         invert = 0;
174         polar_to_rectangular = 1;
175 }
176
177 void PolarConfig::copy_from(PolarConfig &src)
178 {
179         this->angle = src.angle;
180         this->depth = src.depth;
181         this->backwards = src.backwards;
182         this->invert = src.invert;
183         this->polar_to_rectangular = src.polar_to_rectangular;
184 }
185
186 int PolarConfig::equivalent(PolarConfig &src)
187 {
188         return EQUIV(this->angle, src.angle) && EQUIV(this->depth, src.depth);
189 }
190
191 void PolarConfig::interpolate(PolarConfig &prev,
192                 PolarConfig &next,
193                 long prev_frame,
194                 long next_frame,
195                 long current_frame)
196 {
197         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
198         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
199
200         this->depth = prev.depth * prev_scale + next.depth * next_scale;
201         this->angle = prev.angle * prev_scale + next.angle * next_scale;
202 }
203
204
205
206
207
208
209 PolarWindow::PolarWindow(PolarEffect *plugin)
210  : PluginClientWindow(plugin,
211         270,
212         122,
213         270,
214         122,
215         0)
216 {
217         this->plugin = plugin;
218 }
219
220 void PolarWindow::create_objects()
221 {
222         int x = 10, y = 10;
223         add_subwindow(new BC_Title(x, y, _("Depth:")));
224         add_subwindow(depth = new PolarDepth(plugin, x + 50, y));
225         y += 40;
226         add_subwindow(new BC_Title(x, y, _("Angle:")));
227         add_subwindow(angle = new PolarAngle(plugin, x + 50, y));
228         y += 40;
229         add_subwindow(reset = new PolarReset(plugin, this, x, y));
230
231         show_window();
232         flush();
233 }
234
235 // for Reset button
236 void PolarWindow::update()
237 {
238         depth->update(plugin->config.depth);
239         angle->update(plugin->config.angle);
240 }
241
242
243
244
245
246 PolarDepth::PolarDepth(PolarEffect *plugin, int x, int y)
247  : BC_FSlider(x,
248                 y,
249                 0,
250                 200,
251                 200,
252                 (float)1,
253                 (float)100,
254                 plugin->config.depth)
255 {
256         this->plugin = plugin;
257 }
258 int PolarDepth::handle_event()
259 {
260         plugin->config.depth = get_value();
261         plugin->send_configure_change();
262         return 1;
263 }
264
265
266
267
268
269 PolarAngle::PolarAngle(PolarEffect *plugin, int x, int y)
270  : BC_FSlider(x,
271                 y,
272                 0,
273                 200,
274                 200,
275                 (float)1,
276                 (float)360,
277                 plugin->config.angle)
278 {
279         this->plugin = plugin;
280 }
281 int PolarAngle::handle_event()
282 {
283         plugin->config.angle = get_value();
284         plugin->send_configure_change();
285         return 1;
286 }
287
288
289
290 PolarReset::PolarReset(PolarEffect *plugin, PolarWindow *window, int x, int y)
291  : BC_GenericButton(x, y, _("Reset"))
292 {
293         this->plugin = plugin;
294         this->window = window;
295 }
296 PolarReset::~PolarReset()
297 {
298 }
299 int PolarReset::handle_event()
300 {
301         plugin->config.reset();
302         window->update();
303         plugin->send_configure_change();
304         return 1;
305 }
306
307
308
309
310 PolarEffect::PolarEffect(PluginServer *server)
311  : PluginVClient(server)
312 {
313         need_reconfigure = 1;
314         temp_frame = 0;
315         engine = 0;
316
317 }
318
319 PolarEffect::~PolarEffect()
320 {
321
322         if(temp_frame) delete temp_frame;
323         if(engine) delete engine;
324 }
325
326
327
328 const char* PolarEffect::plugin_title() { return N_("Polar"); }
329 int PolarEffect::is_realtime() { return 1; }
330
331
332
333
334 NEW_WINDOW_MACRO(PolarEffect, PolarWindow)
335
336 void PolarEffect::update_gui()
337 {
338         if(thread)
339         {
340                 load_configuration();
341                 thread->window->lock_window();
342                 ((PolarWindow*)thread->window)->angle->update(config.angle);
343                 ((PolarWindow*)thread->window)->depth->update(config.depth);
344                 thread->window->unlock_window();
345         }
346 }
347
348 LOAD_CONFIGURATION_MACRO(PolarEffect, PolarConfig)
349
350
351
352 void PolarEffect::save_data(KeyFrame *keyframe)
353 {
354         FileXML output;
355
356 // cause data to be stored directly in text
357         output.set_shared_output(keyframe->xbuf);
358         output.tag.set_title("POLAR");
359         output.tag.set_property("DEPTH", config.depth);
360         output.tag.set_property("ANGLE", config.angle);
361         output.append_tag();
362         output.tag.set_title("/POLAR");
363         output.append_tag();
364         output.append_newline();
365         output.terminate_string();
366 }
367
368 void PolarEffect::read_data(KeyFrame *keyframe)
369 {
370         FileXML input;
371
372         input.set_shared_input(keyframe->xbuf);
373
374         while(!input.read_tag())
375         {
376                 if(input.tag.title_is("POLAR"))
377                 {
378                         config.depth = input.tag.get_property("DEPTH", config.depth);
379                         config.angle = input.tag.get_property("ANGLE", config.angle);
380                 }
381         }
382 }
383
384 int PolarEffect::process_realtime(VFrame *input, VFrame *output)
385 {
386         need_reconfigure |= load_configuration();
387
388         this->input = input;
389         this->output = output;
390
391         if(EQUIV(config.depth, 0) || EQUIV(config.angle, 0))
392         {
393                 if(input->get_rows()[0] != output->get_rows()[0])
394                         output->copy_from(input);
395         }
396         else
397         {
398                 if(input->get_rows()[0] == output->get_rows()[0])
399                 {
400                         if(!temp_frame)
401                                 temp_frame = new VFrame(input->get_w(), input->get_h(),
402                                         input->get_color_model(), 0);
403                         temp_frame->copy_from(input);
404                         this->input = temp_frame;
405                 }
406
407
408                 if(!engine) engine = new PolarEngine(this, PluginClient::smp + 1);
409
410                 engine->process_packages();
411         }
412         return 0;
413 }
414
415
416
417
418
419 PolarPackage::PolarPackage()
420  : LoadPackage()
421 {
422 }
423
424
425
426
427 PolarUnit::PolarUnit(PolarEffect *plugin, PolarEngine *server)
428  : LoadClient(server)
429 {
430         this->plugin = plugin;
431 }
432
433
434 static int calc_undistorted_coords(int wx,
435                          int wy,
436                          int w,
437                          int h,
438                          float depth,
439                          double angle,
440                          int polar_to_rectangular,
441                          int backwards,
442                          int inverse,
443                          double cen_x,
444                          double cen_y,
445                          double &x,
446                          double &y)
447 {
448         int inside;
449         double phi, phi2;
450         double xx, xm, ym, yy;
451         int xdiff, ydiff;
452         double r;
453         double m;
454         double xmax, ymax, rmax;
455         double x_calc, y_calc;
456         double xi, yi;
457         double circle, angl, t;
458         int x1, x2, y1, y2;
459
460 /* initialize */
461
462         phi = 0.0;
463         r = 0.0;
464
465         x1 = 0;
466         y1 = 0;
467         x2 = w;
468         y2 = h;
469         xdiff = x2 - x1;
470         ydiff = y2 - y1;
471         xm = xdiff / 2.0;
472         ym = ydiff / 2.0;
473         circle = depth;
474         angle = angle;
475         angl = (double)angle / 180.0 * M_PI;
476
477     if(polar_to_rectangular)
478     {
479         if(wx >= cen_x)
480                 {
481                         if(wy > cen_y)
482                 {
483                         phi = M_PI -
484                                         atan(((double)(wx - cen_x)) /
485                                         ((double)(wy - cen_y)));
486                         r   = sqrt(SQR(wx - cen_x) +
487                                         SQR(wy - cen_y));
488                 }
489                         else
490                         if(wy < cen_y)
491                 {
492                         phi = atan(((double)(wx - cen_x)) /
493                                         ((double)(cen_y - wy)));
494                         r   = sqrt(SQR(wx - cen_x) +
495                                         SQR(cen_y - wy));
496                 }
497                         else
498                 {
499                         phi = M_PI / 2;
500                         r   = wx - cen_x;
501                 }
502                 }
503         else
504                 if(wx < cen_x)
505                 {
506                         if(wy < cen_y)
507                 {
508                         phi = 2 * M_PI -
509                                         atan(((double)(cen_x -wx)) /
510                                     ((double)(cen_y - wy)));
511                         r   = sqrt(SQR(cen_x - wx) +
512                                         SQR(cen_y - wy));
513                 }
514                         else
515                         if(wy > cen_y)
516                 {
517                         phi = M_PI +
518                                         atan(((double)(cen_x - wx)) /
519                                         ((double)(wy - cen_y)));
520                         r   = sqrt(SQR(cen_x - wx) +
521                                         SQR(wy - cen_y));
522                 }
523                         else
524                 {
525                         phi = 1.5 * M_PI;
526                         r   = cen_x - wx;
527                 }
528                 }
529         if (wx != cen_x)
530                 {
531                         m = fabs(((double)(wy - cen_y)) /
532                                 ((double)(wx - cen_x)));
533                 }
534         else
535                 {
536                     m = 0;
537                 }
538
539         if(m <= ((double)(y2 - y1) /
540                         (double)(x2 - x1)))
541                 {
542                         if(wx == cen_x)
543                 {
544                         xmax = 0;
545                         ymax = cen_y - y1;
546                 }
547                         else
548                 {
549                         xmax = cen_x - x1;
550                         ymax = m * xmax;
551                 }
552                 }
553         else
554                 {
555                         ymax = cen_y - y1;
556                         xmax = ymax / m;
557                 }
558
559         rmax = sqrt((double)(SQR(xmax) + SQR(ymax)));
560
561         t = ((cen_y - y1) < (cen_x - x1)) ? (cen_y - y1) : (cen_x - x1);
562         rmax = (rmax - t) / 100 * (100 - circle) + t;
563
564         phi = fmod(phi + angl, 2 * M_PI);
565
566         if(backwards)
567                         x_calc = x2 - 1 - (x2 - x1 - 1) / (2 * M_PI) * phi;
568         else
569                         x_calc = (x2 - x1 - 1) / (2 * M_PI) * phi + x1;
570
571         if(inverse)
572                         y_calc = (y2 - y1) / rmax * r + y1;
573         else
574                         y_calc = y2 - (y2 - y1) / rmax * r;
575
576         xi = (int)(x_calc + 0.5);
577         yi = (int)(y_calc + 0.5);
578
579         if(WITHIN(0, xi, w - 1) && WITHIN(0, yi, h - 1))
580                 {
581                         x = x_calc;
582                         y = y_calc;
583
584                         inside = 1;
585                 }
586         else
587                 {
588                         inside = 0;
589                 }
590     }
591         else
592     {
593         if(backwards)
594                         phi = (2 * M_PI) * (x2 - wx) / xdiff;
595         else
596                         phi = (2 * M_PI) * (wx - x1) / xdiff;
597
598         phi = fmod (phi + angl, 2 * M_PI);
599
600         if(phi >= 1.5 * M_PI)
601                         phi2 = 2 * M_PI - phi;
602         else
603                 if (phi >= M_PI)
604                         phi2 = phi - M_PI;
605                 else
606                 if(phi >= 0.5 * M_PI)
607                 phi2 = M_PI - phi;
608                 else
609                 phi2 = phi;
610
611         xx = tan (phi2);
612         if(xx != 0)
613                         m = (double)1.0 / xx;
614         else
615                         m = 0;
616
617         if(m <= ((double)(ydiff) / (double)(xdiff)))
618                 {
619                         if(phi2 == 0)
620                 {
621                         xmax = 0;
622                         ymax = ym - y1;
623                 }
624                         else
625                 {
626                         xmax = xm - x1;
627                         ymax = m * xmax;
628                 }
629                 }
630         else
631                 {
632                         ymax = ym - y1;
633                         xmax = ymax / m;
634                 }
635
636         rmax = sqrt((double)(SQR(xmax) + SQR(ymax)));
637
638         t = ((ym - y1) < (xm - x1)) ? (ym - y1) : (xm - x1);
639
640         rmax = (rmax - t) / 100.0 * (100 - circle) + t;
641
642         if(inverse)
643                         r = rmax * (double)((wy - y1) / (double)(ydiff));
644         else
645                         r = rmax * (double)((y2 - wy) / (double)(ydiff));
646
647         xx = r * sin (phi2);
648         yy = r * cos (phi2);
649
650         if(phi >= 1.5 * M_PI)
651                 {
652                         x_calc = (double)xm - xx;
653                         y_calc = (double)ym - yy;
654                 }
655         else
656                 if(phi >= M_PI)
657                 {
658                 x_calc = (double)xm - xx;
659                 y_calc = (double)ym + yy;
660                 }
661                 else
662                 if(phi >= 0.5 * M_PI)
663             {
664                 x_calc = (double)xm + xx;
665                 y_calc = (double)ym + yy;
666             }
667                 else
668             {
669                 x_calc = (double)xm + xx;
670                 y_calc = (double)ym - yy;
671             }
672
673         xi = (int)(x_calc + 0.5);
674         yi = (int)(y_calc + 0.5);
675
676         if(WITHIN(0, xi, w - 1) &&
677                         WITHIN(0, yi, h - 1))
678                 {
679                         x = x_calc;
680                         y = y_calc;
681
682                         inside = 1;
683         }
684         else
685                 {
686                         inside = 0;
687                 }
688     }
689
690         return inside;
691 }
692
693 static double bilinear(double x, double y, double *values)
694 {
695         double m0, m1;
696         x = fmod(x, 1.0);
697         y = fmod(y, 1.0);
698
699         if(x < 0.0) x += 1.0;
700         if(y < 0.0) y += 1.0;
701
702         m0 = values[0] + x * (values[1] - values[0]);
703         m1 = values[2] + x * (values[3] - values[2]);
704         return m0 + y * (m1 - m0);
705 }
706
707 #define GET_PIXEL(x, y, components, input_rows) \
708         input_rows[CLIP((y), 0, ((h) - 1))] + components * CLIP((x), 0, ((w) - 1))
709
710 #define POLAR_MACRO(type, max, components, chroma_offset) \
711 { \
712         type **in_rows = (type**)plugin->input->get_rows(); \
713         type **out_rows = (type**)plugin->output->get_rows(); \
714         double values[4]; \
715  \
716         for(int y = pkg->row1; y < pkg->row2; y++) \
717         { \
718                 type *output_row = out_rows[y]; \
719  \
720                 for(int x = 0; x < w; x++) \
721                 { \
722                         type *output_pixel = output_row + x * components; \
723                         if(calc_undistorted_coords(x, \
724                                 y, \
725                                 w, \
726                                 h, \
727                                 plugin->config.depth, \
728                                 plugin->config.angle, \
729                                 plugin->config.polar_to_rectangular, \
730                                 plugin->config.backwards, \
731                                 plugin->config.invert, \
732                                 cen_x, \
733                                 cen_y, \
734                                 cx, \
735                                 cy)) \
736                         { \
737                                 type *pixel1 = GET_PIXEL((int)cx,     (int)cy,   components, in_rows); \
738                                 type *pixel2 = GET_PIXEL((int)cx + 1, (int)cy,   components, in_rows); \
739                                 type *pixel3 = GET_PIXEL((int)cx,     (int)cy + 1, components, in_rows); \
740                                 type *pixel4 = GET_PIXEL((int)cx + 1, (int)cy + 1, components, in_rows); \
741  \
742                                 values[0] = pixel1[0]; \
743                                 values[1] = pixel2[0]; \
744                                 values[2] = pixel3[0]; \
745                                 values[3] = pixel4[0]; \
746                                 output_pixel[0] = (type)bilinear(cx, cy, values); \
747  \
748                                 values[0] = pixel1[1]; \
749                                 values[1] = pixel2[1]; \
750                                 values[2] = pixel3[1]; \
751                                 values[3] = pixel4[1]; \
752                                 output_pixel[1] = (type)bilinear(cx, cy, values); \
753  \
754                                 values[0] = pixel1[2]; \
755                                 values[1] = pixel2[2]; \
756                                 values[2] = pixel3[2]; \
757                                 values[3] = pixel4[2]; \
758                                 output_pixel[2] = (type)bilinear(cx, cy, values); \
759  \
760                                 if(components == 4) \
761                                 { \
762                                         values[0] = pixel1[3]; \
763                                         values[1] = pixel2[3]; \
764                                         values[2] = pixel3[3]; \
765                                         values[3] = pixel4[3]; \
766                                         output_pixel[3] = (type)bilinear(cx, cy, values); \
767                                 } \
768                         } \
769                         else \
770                         { \
771                                 output_pixel[0] = 0; \
772                                 output_pixel[1] = chroma_offset; \
773                                 output_pixel[2] = chroma_offset; \
774                                 if(components == 4) output_pixel[3] = max; \
775                         } \
776                 } \
777         } \
778 }
779
780
781 void PolarUnit::process_package(LoadPackage *package)
782 {
783         PolarPackage *pkg = (PolarPackage*)package;
784         int w = plugin->input->get_w();
785         int h = plugin->input->get_h();
786         double cx;
787         double cy;
788         double cen_x = (double)(w - 1) / 2.0;
789         double cen_y = (double)(h - 1) / 2.0;
790
791         switch(plugin->input->get_color_model())
792         {
793                 case BC_RGB_FLOAT:
794                         POLAR_MACRO(float, 1, 3, 0x0)
795                         break;
796                 case BC_RGBA_FLOAT:
797                         POLAR_MACRO(float, 1, 4, 0x0)
798                         break;
799                 case BC_RGB888:
800                         POLAR_MACRO(unsigned char, 0xff, 3, 0x0)
801                         break;
802                 case BC_RGBA8888:
803                         POLAR_MACRO(unsigned char, 0xff, 4, 0x0)
804                         break;
805                 case BC_RGB161616:
806                         POLAR_MACRO(uint16_t, 0xffff, 3, 0x0)
807                         break;
808                 case BC_RGBA16161616:
809                         POLAR_MACRO(uint16_t, 0xffff, 4, 0x0)
810                         break;
811                 case BC_YUV888:
812                         POLAR_MACRO(unsigned char, 0xff, 3, 0x80)
813                         break;
814                 case BC_YUVA8888:
815                         POLAR_MACRO(unsigned char, 0xff, 4, 0x80)
816                         break;
817                 case BC_YUV161616:
818                         POLAR_MACRO(uint16_t, 0xffff, 3, 0x8000)
819                         break;
820                 case BC_YUVA16161616:
821                         POLAR_MACRO(uint16_t, 0xffff, 4, 0x8000)
822                         break;
823         }
824 }
825
826
827
828
829 PolarEngine::PolarEngine(PolarEffect *plugin, int cpus)
830  : LoadServer(cpus, cpus)
831 {
832         this->plugin = plugin;
833 }
834
835 void PolarEngine::init_packages()
836 {
837         for(int i = 0; i < LoadServer::get_total_packages(); i++)
838         {
839                 PolarPackage *pkg = (PolarPackage*)get_package(i);
840                 pkg->row1 = plugin->input->get_h() * i / LoadServer::get_total_packages();
841                 pkg->row2 = plugin->input->get_h() * (i + 1) / LoadServer::get_total_packages();
842         }
843 }
844
845 LoadClient* PolarEngine::new_client()
846 {
847         return new PolarUnit(plugin, this);
848 }
849
850 LoadPackage* PolarEngine::new_package()
851 {
852         return new PolarPackage;
853 }
854
855
856