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