initial commit
[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
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 N_("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->xbuf);
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->xbuf);
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)
358                                 temp_frame = new VFrame(input->get_w(), input->get_h(),
359                                         input->get_color_model(), 0);
360                         temp_frame->copy_from(input);
361                         this->input = temp_frame;
362                 }
363
364
365                 if(!engine) engine = new PolarEngine(this, PluginClient::smp + 1);
366
367                 engine->process_packages();
368         }
369         return 0;
370 }
371
372
373
374
375
376 PolarPackage::PolarPackage()
377  : LoadPackage()
378 {
379 }
380
381
382
383
384 PolarUnit::PolarUnit(PolarEffect *plugin, PolarEngine *server)
385  : LoadClient(server)
386 {
387         this->plugin = plugin;
388 }
389
390
391 static int calc_undistorted_coords(int wx,
392                          int wy,
393                          int w,
394                          int h,
395                          float depth,
396                          double angle,
397                          int polar_to_rectangular,
398                          int backwards,
399                          int inverse,
400                          double cen_x,
401                          double cen_y,
402                          double &x,
403                          double &y)
404 {
405         int inside;
406         double phi, phi2;
407         double xx, xm, ym, yy;
408         int xdiff, ydiff;
409         double r;
410         double m;
411         double xmax, ymax, rmax;
412         double x_calc, y_calc;
413         double xi, yi;
414         double circle, angl, t;
415         int x1, x2, y1, y2;
416
417 /* initialize */
418
419         phi = 0.0;
420         r = 0.0;
421
422         x1 = 0;
423         y1 = 0;
424         x2 = w;
425         y2 = h;
426         xdiff = x2 - x1;
427         ydiff = y2 - y1;
428         xm = xdiff / 2.0;
429         ym = ydiff / 2.0;
430         circle = depth;
431         angle = angle;
432         angl = (double)angle / 180.0 * M_PI;
433
434     if(polar_to_rectangular)
435     {
436         if(wx >= cen_x)
437                 {
438                         if(wy > cen_y)
439                 {
440                         phi = M_PI -
441                                         atan(((double)(wx - cen_x)) /
442                                         ((double)(wy - cen_y)));
443                         r   = sqrt(SQR(wx - cen_x) +
444                                         SQR(wy - cen_y));
445                 }
446                         else
447                         if(wy < cen_y)
448                 {
449                         phi = atan(((double)(wx - cen_x)) /
450                                         ((double)(cen_y - wy)));
451                         r   = sqrt(SQR(wx - cen_x) +
452                                         SQR(cen_y - wy));
453                 }
454                         else
455                 {
456                         phi = M_PI / 2;
457                         r   = wx - cen_x;
458                 }
459                 }
460         else
461                 if(wx < cen_x)
462                 {
463                         if(wy < cen_y)
464                 {
465                         phi = 2 * M_PI -
466                                         atan(((double)(cen_x -wx)) /
467                                     ((double)(cen_y - wy)));
468                         r   = sqrt(SQR(cen_x - wx) +
469                                         SQR(cen_y - wy));
470                 }
471                         else
472                         if(wy > cen_y)
473                 {
474                         phi = M_PI +
475                                         atan(((double)(cen_x - wx)) /
476                                         ((double)(wy - cen_y)));
477                         r   = sqrt(SQR(cen_x - wx) +
478                                         SQR(wy - cen_y));
479                 }
480                         else
481                 {
482                         phi = 1.5 * M_PI;
483                         r   = cen_x - wx;
484                 }
485                 }
486         if (wx != cen_x)
487                 {
488                         m = fabs(((double)(wy - cen_y)) /
489                                 ((double)(wx - cen_x)));
490                 }
491         else
492                 {
493                     m = 0;
494                 }
495
496         if(m <= ((double)(y2 - y1) /
497                         (double)(x2 - x1)))
498                 {
499                         if(wx == cen_x)
500                 {
501                         xmax = 0;
502                         ymax = cen_y - y1;
503                 }
504                         else
505                 {
506                         xmax = cen_x - x1;
507                         ymax = m * xmax;
508                 }
509                 }
510         else
511                 {
512                         ymax = cen_y - y1;
513                         xmax = ymax / m;
514                 }
515
516         rmax = sqrt((double)(SQR(xmax) + SQR(ymax)));
517
518         t = ((cen_y - y1) < (cen_x - x1)) ? (cen_y - y1) : (cen_x - x1);
519         rmax = (rmax - t) / 100 * (100 - circle) + t;
520
521         phi = fmod(phi + angl, 2 * M_PI);
522
523         if(backwards)
524                         x_calc = x2 - 1 - (x2 - x1 - 1) / (2 * M_PI) * phi;
525         else
526                         x_calc = (x2 - x1 - 1) / (2 * M_PI) * phi + x1;
527
528         if(inverse)
529                         y_calc = (y2 - y1) / rmax * r + y1;
530         else
531                         y_calc = y2 - (y2 - y1) / rmax * r;
532
533         xi = (int)(x_calc + 0.5);
534         yi = (int)(y_calc + 0.5);
535
536         if(WITHIN(0, xi, w - 1) && WITHIN(0, yi, h - 1))
537                 {
538                         x = x_calc;
539                         y = y_calc;
540
541                         inside = 1;
542                 }
543         else
544                 {
545                         inside = 0;
546                 }
547     }
548         else
549     {
550         if(backwards)
551                         phi = (2 * M_PI) * (x2 - wx) / xdiff;
552         else
553                         phi = (2 * M_PI) * (wx - x1) / xdiff;
554
555         phi = fmod (phi + angl, 2 * M_PI);
556
557         if(phi >= 1.5 * M_PI)
558                         phi2 = 2 * M_PI - phi;
559         else
560                 if (phi >= M_PI)
561                         phi2 = phi - M_PI;
562                 else
563                 if(phi >= 0.5 * M_PI)
564                 phi2 = M_PI - phi;
565                 else
566                 phi2 = phi;
567
568         xx = tan (phi2);
569         if(xx != 0)
570                         m = (double)1.0 / xx;
571         else
572                         m = 0;
573
574         if(m <= ((double)(ydiff) / (double)(xdiff)))
575                 {
576                         if(phi2 == 0)
577                 {
578                         xmax = 0;
579                         ymax = ym - y1;
580                 }
581                         else
582                 {
583                         xmax = xm - x1;
584                         ymax = m * xmax;
585                 }
586                 }
587         else
588                 {
589                         ymax = ym - y1;
590                         xmax = ymax / m;
591                 }
592
593         rmax = sqrt((double)(SQR(xmax) + SQR(ymax)));
594
595         t = ((ym - y1) < (xm - x1)) ? (ym - y1) : (xm - x1);
596
597         rmax = (rmax - t) / 100.0 * (100 - circle) + t;
598
599         if(inverse)
600                         r = rmax * (double)((wy - y1) / (double)(ydiff));
601         else
602                         r = rmax * (double)((y2 - wy) / (double)(ydiff));
603
604         xx = r * sin (phi2);
605         yy = r * cos (phi2);
606
607         if(phi >= 1.5 * M_PI)
608                 {
609                         x_calc = (double)xm - xx;
610                         y_calc = (double)ym - yy;
611                 }
612         else
613                 if(phi >= M_PI)
614                 {
615                 x_calc = (double)xm - xx;
616                 y_calc = (double)ym + yy;
617                 }
618                 else
619                 if(phi >= 0.5 * M_PI)
620             {
621                 x_calc = (double)xm + xx;
622                 y_calc = (double)ym + yy;
623             }
624                 else
625             {
626                 x_calc = (double)xm + xx;
627                 y_calc = (double)ym - yy;
628             }
629
630         xi = (int)(x_calc + 0.5);
631         yi = (int)(y_calc + 0.5);
632
633         if(WITHIN(0, xi, w - 1) &&
634                         WITHIN(0, yi, h - 1))
635                 {
636                         x = x_calc;
637                         y = y_calc;
638
639                         inside = 1;
640         }
641         else
642                 {
643                         inside = 0;
644                 }
645     }
646
647         return inside;
648 }
649
650 static double bilinear(double x, double y, double *values)
651 {
652         double m0, m1;
653         x = fmod(x, 1.0);
654         y = fmod(y, 1.0);
655
656         if(x < 0.0) x += 1.0;
657         if(y < 0.0) y += 1.0;
658
659         m0 = values[0] + x * (values[1] - values[0]);
660         m1 = values[2] + x * (values[3] - values[2]);
661         return m0 + y * (m1 - m0);
662 }
663
664 #define GET_PIXEL(x, y, components, input_rows) \
665         input_rows[CLIP((y), 0, ((h) - 1))] + components * CLIP((x), 0, ((w) - 1))
666
667 #define POLAR_MACRO(type, max, components, chroma_offset) \
668 { \
669         type **in_rows = (type**)plugin->input->get_rows(); \
670         type **out_rows = (type**)plugin->output->get_rows(); \
671         double values[4]; \
672  \
673         for(int y = pkg->row1; y < pkg->row2; y++) \
674         { \
675                 type *output_row = out_rows[y]; \
676  \
677                 for(int x = 0; x < w; x++) \
678                 { \
679                         type *output_pixel = output_row + x * components; \
680                         if(calc_undistorted_coords(x, \
681                                 y, \
682                                 w, \
683                                 h, \
684                                 plugin->config.depth, \
685                                 plugin->config.angle, \
686                                 plugin->config.polar_to_rectangular, \
687                                 plugin->config.backwards, \
688                                 plugin->config.invert, \
689                                 cen_x, \
690                                 cen_y, \
691                                 cx, \
692                                 cy)) \
693                         { \
694                                 type *pixel1 = GET_PIXEL((int)cx,     (int)cy,   components, in_rows); \
695                                 type *pixel2 = GET_PIXEL((int)cx + 1, (int)cy,   components, in_rows); \
696                                 type *pixel3 = GET_PIXEL((int)cx,     (int)cy + 1, components, in_rows); \
697                                 type *pixel4 = GET_PIXEL((int)cx + 1, (int)cy + 1, components, in_rows); \
698  \
699                                 values[0] = pixel1[0]; \
700                                 values[1] = pixel2[0]; \
701                                 values[2] = pixel3[0]; \
702                                 values[3] = pixel4[0]; \
703                                 output_pixel[0] = (type)bilinear(cx, cy, values); \
704  \
705                                 values[0] = pixel1[1]; \
706                                 values[1] = pixel2[1]; \
707                                 values[2] = pixel3[1]; \
708                                 values[3] = pixel4[1]; \
709                                 output_pixel[1] = (type)bilinear(cx, cy, values); \
710  \
711                                 values[0] = pixel1[2]; \
712                                 values[1] = pixel2[2]; \
713                                 values[2] = pixel3[2]; \
714                                 values[3] = pixel4[2]; \
715                                 output_pixel[2] = (type)bilinear(cx, cy, values); \
716  \
717                                 if(components == 4) \
718                                 { \
719                                         values[0] = pixel1[3]; \
720                                         values[1] = pixel2[3]; \
721                                         values[2] = pixel3[3]; \
722                                         values[3] = pixel4[3]; \
723                                         output_pixel[3] = (type)bilinear(cx, cy, values); \
724                                 } \
725                         } \
726                         else \
727                         { \
728                                 output_pixel[0] = 0; \
729                                 output_pixel[1] = chroma_offset; \
730                                 output_pixel[2] = chroma_offset; \
731                                 if(components == 4) output_pixel[3] = max; \
732                         } \
733                 } \
734         } \
735 }
736
737
738 void PolarUnit::process_package(LoadPackage *package)
739 {
740         PolarPackage *pkg = (PolarPackage*)package;
741         int w = plugin->input->get_w();
742         int h = plugin->input->get_h();
743         double cx;
744         double cy;
745         double cen_x = (double)(w - 1) / 2.0;
746         double cen_y = (double)(h - 1) / 2.0;
747
748         switch(plugin->input->get_color_model())
749         {
750                 case BC_RGB_FLOAT:
751                         POLAR_MACRO(float, 1, 3, 0x0)
752                         break;
753                 case BC_RGBA_FLOAT:
754                         POLAR_MACRO(float, 1, 4, 0x0)
755                         break;
756                 case BC_RGB888:
757                         POLAR_MACRO(unsigned char, 0xff, 3, 0x0)
758                         break;
759                 case BC_RGBA8888:
760                         POLAR_MACRO(unsigned char, 0xff, 4, 0x0)
761                         break;
762                 case BC_RGB161616:
763                         POLAR_MACRO(uint16_t, 0xffff, 3, 0x0)
764                         break;
765                 case BC_RGBA16161616:
766                         POLAR_MACRO(uint16_t, 0xffff, 4, 0x0)
767                         break;
768                 case BC_YUV888:
769                         POLAR_MACRO(unsigned char, 0xff, 3, 0x80)
770                         break;
771                 case BC_YUVA8888:
772                         POLAR_MACRO(unsigned char, 0xff, 4, 0x80)
773                         break;
774                 case BC_YUV161616:
775                         POLAR_MACRO(uint16_t, 0xffff, 3, 0x8000)
776                         break;
777                 case BC_YUVA16161616:
778                         POLAR_MACRO(uint16_t, 0xffff, 4, 0x8000)
779                         break;
780         }
781 }
782
783
784
785
786 PolarEngine::PolarEngine(PolarEffect *plugin, int cpus)
787  : LoadServer(cpus, cpus)
788 {
789         this->plugin = plugin;
790 }
791
792 void PolarEngine::init_packages()
793 {
794         for(int i = 0; i < LoadServer::get_total_packages(); i++)
795         {
796                 PolarPackage *pkg = (PolarPackage*)get_package(i);
797                 pkg->row1 = plugin->input->get_h() * i / LoadServer::get_total_packages();
798                 pkg->row2 = plugin->input->get_h() * (i + 1) / LoadServer::get_total_packages();
799         }
800 }
801
802 LoadClient* PolarEngine::new_client()
803 {
804         return new PolarUnit(plugin, this);
805 }
806
807 LoadPackage* PolarEngine::new_package()
808 {
809         return new PolarPackage;
810 }
811
812
813