r860: Merge 2.1:
[cinelerra_cv.git] / plugins / polar / polar.C
blob3ca71079cdca25b239184ff58b546e103c6d2798
1 #include "bcdisplayinfo.h"
2 #include "clip.h"
3 #include "bchash.h"
4 #include "filexml.h"
5 #include "guicast.h"
6 #include "keyframe.h"
7 #include "language.h"
8 #include "loadbalance.h"
9 #include "picon_png.h"
10 #include "pluginvclient.h"
11 #include "vframe.h"
15 #include <string.h>
16 #include <stdint.h>
19 #define SQR(x) ((x) * (x))
20 #define WITHIN(a, b, c) ((((a) <= (b)) && ((b) <= (c))) ? 1 : 0)
23 class PolarEffect;
24 class PolarEngine;
25 class PolarWindow;
28 class PolarConfig
30 public:
31         PolarConfig();
33         void copy_from(PolarConfig &src);
34         int equivalent(PolarConfig &src);
35         void interpolate(PolarConfig &prev, 
36                 PolarConfig &next, 
37                 long prev_frame, 
38                 long next_frame, 
39                 long current_frame);
40         
41         int polar_to_rectangular;
42         float depth;
43         float angle;
44         int backwards;
45         int invert;
50 class PolarDepth : public BC_FSlider
52 public:
53         PolarDepth(PolarEffect *plugin, int x, int y);
54         int handle_event();
55         PolarEffect *plugin;
58 class PolarAngle : public BC_FSlider
60 public:
61         PolarAngle(PolarEffect *plugin, int x, int y);
62         int handle_event();
63         PolarEffect *plugin;
66 class PolarWindow : public BC_Window
68 public:
69         PolarWindow(PolarEffect *plugin, int x, int y);
70         void create_objects();
71         int close_event();
72         PolarEffect *plugin;
73         PolarDepth *depth;
74         PolarAngle *angle;
78 PLUGIN_THREAD_HEADER(PolarEffect, PolarThread, PolarWindow)
81 class PolarPackage : public LoadPackage
83 public:
84         PolarPackage();
85         int row1, row2;
88 class PolarUnit : public LoadClient
90 public:
91         PolarUnit(PolarEffect *plugin, PolarEngine *server);
92         void process_package(LoadPackage *package);
93         PolarEffect *plugin;
96 class PolarEngine : public LoadServer
98 public:
99         PolarEngine(PolarEffect *plugin, int cpus);
100         void init_packages();
101         LoadClient* new_client();
102         LoadPackage* new_package();
103         PolarEffect *plugin;
106 class PolarEffect : public PluginVClient
108 public:
109         PolarEffect(PluginServer *server);
110         ~PolarEffect();
112         int process_realtime(VFrame *input, VFrame *output);
113         int is_realtime();
114         char* plugin_title();
115         VFrame* new_picon();
116         int load_configuration();
117         int load_defaults();
118         int save_defaults();
119         void save_data(KeyFrame *keyframe);
120         void read_data(KeyFrame *keyframe);
121         int show_gui();
122         int set_string();
123         void raise_window();
124         void update_gui();
126         PolarConfig config;
127         BC_Hash *defaults;
128         PolarThread *thread;
129         PolarEngine *engine;
130         VFrame *temp_frame;
131         VFrame *input, *output;
132         int need_reconfigure;
137 REGISTER_PLUGIN(PolarEffect)
141 PolarConfig::PolarConfig()
143         angle = 0.0;
144         depth = 0.0;
145         backwards = 0;
146         invert = 0;
147         polar_to_rectangular = 1;
151 void PolarConfig::copy_from(PolarConfig &src)
153         this->angle = src.angle;
154         this->depth = src.depth;
155         this->backwards = src.backwards;
156         this->invert = src.invert;
157         this->polar_to_rectangular = src.polar_to_rectangular;
160 int PolarConfig::equivalent(PolarConfig &src)
162         return EQUIV(this->angle, src.angle) && EQUIV(this->depth, src.depth);
165 void PolarConfig::interpolate(PolarConfig &prev, 
166                 PolarConfig &next, 
167                 long prev_frame, 
168                 long next_frame, 
169                 long current_frame)
171         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
172         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
174         this->depth = prev.depth * prev_scale + next.depth * next_scale;
175         this->angle = prev.angle * prev_scale + next.angle * next_scale;
183 PolarWindow::PolarWindow(PolarEffect *plugin, int x, int y)
184  : BC_Window(plugin->gui_string, 
185         x, 
186         y, 
187         270, 
188         100, 
189         270, 
190         100, 
191         0, 
192         0,
193         1)
195         this->plugin = plugin;
198 void PolarWindow::create_objects()
200         int x = 10, y = 10;
201         add_subwindow(new BC_Title(x, y, _("Depth:")));
202         add_subwindow(depth = new PolarDepth(plugin, x + 50, y));
203         y += 40;
204         add_subwindow(new BC_Title(x, y, _("Angle:")));
205         add_subwindow(angle = new PolarAngle(plugin, x + 50, y));
207         show_window();
208         flush();
211 WINDOW_CLOSE_EVENT(PolarWindow)
213 PLUGIN_THREAD_OBJECT(PolarEffect, PolarThread, PolarWindow)
216 PolarDepth::PolarDepth(PolarEffect *plugin, int x, int y)
217  : BC_FSlider(x, 
218                 y, 
219                 0,
220                 200,
221                 200, 
222                 (float)1, 
223                 (float)100,
224                 plugin->config.depth)
226         this->plugin = plugin;
228 int PolarDepth::handle_event()
230         plugin->config.depth = get_value();
231         plugin->send_configure_change();
232         return 1;
239 PolarAngle::PolarAngle(PolarEffect *plugin, int x, int y)
240  : BC_FSlider(x, 
241                 y, 
242                 0,
243                 200,
244                 200, 
245                 (float)1, 
246                 (float)360, 
247                 plugin->config.angle)
249         this->plugin = plugin;
251 int PolarAngle::handle_event()
253         plugin->config.angle = get_value();
254         plugin->send_configure_change();
255         return 1;
262 PolarEffect::PolarEffect(PluginServer *server)
263  : PluginVClient(server)
265         need_reconfigure = 1;
266         temp_frame = 0;
267         engine = 0;
268         PLUGIN_CONSTRUCTOR_MACRO
271 PolarEffect::~PolarEffect()
273         PLUGIN_DESTRUCTOR_MACRO
274         if(temp_frame) delete temp_frame;
275         if(engine) delete engine;
280 char* PolarEffect::plugin_title() { return N_("Polar"); }
281 int PolarEffect::is_realtime() { return 1; }
285 NEW_PICON_MACRO(PolarEffect)
287 SHOW_GUI_MACRO(PolarEffect, PolarThread)
289 RAISE_WINDOW_MACRO(PolarEffect)
291 SET_STRING_MACRO(PolarEffect)
293 void PolarEffect::update_gui()
295         if(thread)
296         {
297                 load_configuration();
298                 thread->window->lock_window();
299                 thread->window->angle->update(config.angle);
300                 thread->window->depth->update(config.depth);
301                 thread->window->unlock_window();
302         }
305 LOAD_CONFIGURATION_MACRO(PolarEffect, PolarConfig)
308 int PolarEffect::load_defaults()
310         char directory[BCTEXTLEN];
311 // set the default directory
312         sprintf(directory, "%spolar.rc", BCASTDIR);
314 // load the defaults
315         defaults = new BC_Hash(directory);
316         defaults->load();
318         config.depth = defaults->get("DEPTH", config.depth);
319         config.angle = defaults->get("ANGLE", config.angle);
320         return 0;
323 int PolarEffect::save_defaults()
325         defaults->update("DEPTH", config.depth);
326         defaults->update("ANGLE", config.angle);
327         defaults->save();
328         return 0;
331 void PolarEffect::save_data(KeyFrame *keyframe)
333         FileXML output;
335 // cause data to be stored directly in text
336         output.set_shared_string(keyframe->data, MESSAGESIZE);
337         output.tag.set_title("POLAR");
338         output.tag.set_property("DEPTH", config.depth);
339         output.tag.set_property("ANGLE", config.angle);
340         output.append_tag();
341         output.terminate_string();
344 void PolarEffect::read_data(KeyFrame *keyframe)
346         FileXML input;
348         input.set_shared_string(keyframe->data, strlen(keyframe->data));
350         int result = 0;
352         while(!input.read_tag())
353         {
354                 if(input.tag.title_is("POLAR"))
355                 {
356                         config.depth = input.tag.get_property("DEPTH", config.depth);
357                         config.angle = input.tag.get_property("ANGLE", config.angle);
358                 }
359         }
362 int PolarEffect::process_realtime(VFrame *input, VFrame *output)
364         need_reconfigure |= load_configuration();
366         this->input = input;
367         this->output = output;
369         if(EQUIV(config.depth, 0) || EQUIV(config.angle, 0))
370         {
371                 if(input->get_rows()[0] != output->get_rows()[0])
372                         output->copy_from(input);
373         }
374         else
375         {
376                 if(input->get_rows()[0] == output->get_rows()[0])
377                 {
378                         if(!temp_frame) temp_frame = new VFrame(0,
379                                 input->get_w(),
380                                 input->get_h(),
381                                 input->get_color_model());
382                         temp_frame->copy_from(input);
383                         this->input = temp_frame;
384                 }
385                 
386                 
387                 if(!engine) engine = new PolarEngine(this, PluginClient::smp + 1);
389                 engine->process_packages();
390         }
391         return 0;
398 PolarPackage::PolarPackage()
399  : LoadPackage()
406 PolarUnit::PolarUnit(PolarEffect *plugin, PolarEngine *server)
407  : LoadClient(server)
409         this->plugin = plugin;
413 static int calc_undistorted_coords(int wx,
414                          int wy,
415                          int w,
416                          int h,
417                          float depth,
418                          double angle,
419                          int polar_to_rectangular,
420                          int backwards,
421                          int inverse,
422                          double cen_x,
423                          double cen_y,
424                          double &x,
425                          double &y)
427         int inside;
428         double phi, phi2;
429         double xx, xm, ym, yy;
430         int xdiff, ydiff;
431         double r;
432         double m;
433         double xmax, ymax, rmax;
434         double x_calc, y_calc;
435         double xi, yi;
436         double circle, angl, t;
437         int x1, x2, y1, y2;
439 /* initialize */
441         phi = 0.0;
442         r = 0.0;
444         x1 = 0;
445         y1 = 0;
446         x2 = w;
447         y2 = h;
448         xdiff = x2 - x1;
449         ydiff = y2 - y1;
450         xm = xdiff / 2.0;
451         ym = ydiff / 2.0;
452         circle = depth;
453         angle = angle;
454         angl = (double)angle / 180.0 * M_PI;
456     if(polar_to_rectangular)
457     {
458         if(wx >= cen_x)
459                 {
460                         if(wy > cen_y)
461                 {
462                         phi = M_PI - 
463                                         atan(((double)(wx - cen_x)) / 
464                                         ((double)(wy - cen_y)));
465                         r   = sqrt(SQR(wx - cen_x) + 
466                                         SQR(wy - cen_y));
467                 }
468                         else 
469                         if(wy < cen_y)
470                 {
471                         phi = atan(((double)(wx - cen_x)) / 
472                                         ((double)(cen_y - wy)));
473                         r   = sqrt(SQR(wx - cen_x) + 
474                                         SQR(cen_y - wy));
475                 }
476                         else
477                 {
478                         phi = M_PI / 2;
479                         r   = wx - cen_x;
480                 }
481                 }
482         else 
483                 if(wx < cen_x)
484                 {
485                         if(wy < cen_y)
486                 {
487                         phi = 2 * M_PI - 
488                                         atan(((double)(cen_x -wx)) /
489                                     ((double)(cen_y - wy)));
490                         r   = sqrt(SQR(cen_x - wx) + 
491                                         SQR(cen_y - wy));
492                 }
493                         else 
494                         if(wy > cen_y)
495                 {
496                         phi = M_PI + 
497                                         atan(((double)(cen_x - wx)) / 
498                                         ((double)(wy - cen_y)));
499                         r   = sqrt(SQR(cen_x - wx) + 
500                                         SQR(wy - cen_y));
501                 }
502                         else
503                 {
504                         phi = 1.5 * M_PI;
505                         r   = cen_x - wx;
506                 }
507                 }
508         if (wx != cen_x)
509                 {
510                         m = fabs(((double)(wy - cen_y)) / 
511                                 ((double)(wx - cen_x)));
512                 }
513         else
514                 {
515                     m = 0;
516                 }
517     
518         if(m <= ((double)(y2 - y1) / 
519                         (double)(x2 - x1)))
520                 {
521                         if(wx == cen_x)
522                 {
523                         xmax = 0;
524                         ymax = cen_y - y1;
525                 }
526                         else
527                 {
528                         xmax = cen_x - x1;
529                         ymax = m * xmax;
530                 }
531                 }
532         else
533                 {
534                         ymax = cen_y - y1;
535                         xmax = ymax / m;
536                 }
537     
538         rmax = sqrt((double)(SQR(xmax) + SQR(ymax)));
540         t = ((cen_y - y1) < (cen_x - x1)) ? (cen_y - y1) : (cen_x - x1);
541         rmax = (rmax - t) / 100 * (100 - circle) + t;
543         phi = fmod(phi + angl, 2 * M_PI);
545         if(backwards)
546                         x_calc = x2 - 1 - (x2 - x1 - 1) / (2 * M_PI) * phi;
547         else
548                         x_calc = (x2 - x1 - 1) / (2 * M_PI) * phi + x1;
550         if(inverse)
551                         y_calc = (y2 - y1) / rmax * r + y1;
552         else
553                         y_calc = y2 - (y2 - y1) / rmax * r;
555         xi = (int)(x_calc + 0.5);
556         yi = (int)(y_calc + 0.5);
557     
558         if(WITHIN(0, xi, w - 1) && WITHIN(0, yi, h - 1))
559                 {
560                         x = x_calc;
561                         y = y_calc;
563                         inside = 1;
564                 }
565         else
566                 {
567                         inside = 0;
568                 }
569     }
570         else
571     {
572         if(backwards)
573                         phi = (2 * M_PI) * (x2 - wx) / xdiff;
574         else
575                         phi = (2 * M_PI) * (wx - x1) / xdiff;
577         phi = fmod (phi + angl, 2 * M_PI);
578     
579         if(phi >= 1.5 * M_PI)
580                         phi2 = 2 * M_PI - phi;
581         else
582                 if (phi >= M_PI)
583                         phi2 = phi - M_PI;
584                 else
585                 if(phi >= 0.5 * M_PI)
586                 phi2 = M_PI - phi;
587                 else
588                 phi2 = phi;
590         xx = tan (phi2);
591         if(xx != 0)
592                         m = (double)1.0 / xx;
593         else
594                         m = 0;
595     
596         if(m <= ((double)(ydiff) / (double)(xdiff)))
597                 {
598                         if(phi2 == 0)
599                 {
600                         xmax = 0;
601                         ymax = ym - y1;
602                 }
603                         else
604                 {
605                         xmax = xm - x1;
606                         ymax = m * xmax;
607                 }
608                 }
609         else
610                 {
611                         ymax = ym - y1;
612                         xmax = ymax / m;
613                 }
614     
615         rmax = sqrt((double)(SQR(xmax) + SQR(ymax)));
616     
617         t = ((ym - y1) < (xm - x1)) ? (ym - y1) : (xm - x1);
619         rmax = (rmax - t) / 100.0 * (100 - circle) + t;
621         if(inverse)
622                         r = rmax * (double)((wy - y1) / (double)(ydiff));
623         else
624                         r = rmax * (double)((y2 - wy) / (double)(ydiff));
625     
626         xx = r * sin (phi2);
627         yy = r * cos (phi2);
629         if(phi >= 1.5 * M_PI)
630                 {
631                         x_calc = (double)xm - xx;
632                         y_calc = (double)ym - yy;
633                 }
634         else
635                 if(phi >= M_PI)
636                 {
637                 x_calc = (double)xm - xx;
638                 y_calc = (double)ym + yy;
639                 }
640                 else
641                 if(phi >= 0.5 * M_PI)
642             {
643                 x_calc = (double)xm + xx;
644                 y_calc = (double)ym + yy;
645             }
646                 else
647             {
648                 x_calc = (double)xm + xx;
649                 y_calc = (double)ym - yy;
650             }
652         xi = (int)(x_calc + 0.5);
653         yi = (int)(y_calc + 0.5);
654   
655         if(WITHIN(0, xi, w - 1) && 
656                         WITHIN(0, yi, h - 1)) 
657                 {
658                         x = x_calc;
659                         y = y_calc;
661                         inside = 1;
662         }
663         else
664                 {
665                         inside = 0;
666                 }
667     }
669         return inside;
672 static double bilinear(double x, double y, double *values)
674         double m0, m1;
675         x = fmod(x, 1.0);
676         y = fmod(y, 1.0);
678         if(x < 0.0) x += 1.0;
679         if(y < 0.0) y += 1.0;
681         m0 = values[0] + x * (values[1] - values[0]);
682         m1 = values[2] + x * (values[3] - values[2]);
683         return m0 + y * (m1 - m0);
686 #define GET_PIXEL(x, y, components, input_rows) \
687         input_rows[CLIP((y), 0, ((h) - 1))] + components * CLIP((x), 0, ((w) - 1))
689 #define POLAR_MACRO(type, max, components, chroma_offset) \
690 { \
691         type **in_rows = (type**)plugin->input->get_rows(); \
692         type **out_rows = (type**)plugin->output->get_rows(); \
693         double values[4]; \
695         for(int y = pkg->row1; y < pkg->row2; y++) \
696         { \
697                 type *output_row = out_rows[y]; \
699                 for(int x = 0; x < w; x++) \
700                 { \
701                         type *output_pixel = output_row + x * components; \
702                         if(calc_undistorted_coords(x, \
703                                 y, \
704                                 w, \
705                                 h, \
706                                 plugin->config.depth, \
707                                 plugin->config.angle, \
708                                 plugin->config.polar_to_rectangular, \
709                                 plugin->config.backwards, \
710                                 plugin->config.invert, \
711                                 cen_x, \
712                                 cen_y, \
713                                 cx, \
714                                 cy)) \
715                         { \
716                                 type *pixel1 = GET_PIXEL((int)cx,     (int)cy,   components, in_rows); \
717                                 type *pixel2 = GET_PIXEL((int)cx + 1, (int)cy,   components, in_rows); \
718                                 type *pixel3 = GET_PIXEL((int)cx,     (int)cy + 1, components, in_rows); \
719                                 type *pixel4 = GET_PIXEL((int)cx + 1, (int)cy + 1, components, in_rows); \
721                                 values[0] = pixel1[0]; \
722                                 values[1] = pixel2[0]; \
723                                 values[2] = pixel3[0]; \
724                                 values[3] = pixel4[0]; \
725                                 output_pixel[0] = (type)bilinear(cx, cy, values); \
727                                 values[0] = pixel1[1]; \
728                                 values[1] = pixel2[1]; \
729                                 values[2] = pixel3[1]; \
730                                 values[3] = pixel4[1]; \
731                                 output_pixel[1] = (type)bilinear(cx, cy, values); \
733                                 values[0] = pixel1[2]; \
734                                 values[1] = pixel2[2]; \
735                                 values[2] = pixel3[2]; \
736                                 values[3] = pixel4[2]; \
737                                 output_pixel[2] = (type)bilinear(cx, cy, values); \
739                                 if(components == 4) \
740                                 { \
741                                         values[0] = pixel1[3]; \
742                                         values[1] = pixel2[3]; \
743                                         values[2] = pixel3[3]; \
744                                         values[3] = pixel4[3]; \
745                                         output_pixel[3] = (type)bilinear(cx, cy, values); \
746                                 } \
747                         } \
748                         else \
749                         { \
750                                 output_pixel[0] = 0; \
751                                 output_pixel[1] = chroma_offset; \
752                                 output_pixel[2] = chroma_offset; \
753                                 if(components == 4) output_pixel[3] = max; \
754                         } \
755                 } \
756         } \
760 void PolarUnit::process_package(LoadPackage *package)
762         PolarPackage *pkg = (PolarPackage*)package;
763         int w = plugin->input->get_w();
764         int h = plugin->input->get_h();
765         double cx;
766         double cy;
767         double cen_x = (double)(w - 1) / 2.0;
768         double cen_y = (double)(h - 1) / 2.0;
769         
770         switch(plugin->input->get_color_model())
771         {
772                 case BC_RGB_FLOAT:
773                         POLAR_MACRO(float, 1, 3, 0x0)
774                         break;
775                 case BC_RGBA_FLOAT:
776                         POLAR_MACRO(float, 1, 4, 0x0)
777                         break;
778                 case BC_RGB888:
779                         POLAR_MACRO(unsigned char, 0xff, 3, 0x0)
780                         break;
781                 case BC_RGBA8888:
782                         POLAR_MACRO(unsigned char, 0xff, 4, 0x0)
783                         break;
784                 case BC_RGB161616:
785                         POLAR_MACRO(uint16_t, 0xffff, 3, 0x0)
786                         break;
787                 case BC_RGBA16161616:
788                         POLAR_MACRO(uint16_t, 0xffff, 4, 0x0)
789                         break;
790                 case BC_YUV888:
791                         POLAR_MACRO(unsigned char, 0xff, 3, 0x80)
792                         break;
793                 case BC_YUVA8888:
794                         POLAR_MACRO(unsigned char, 0xff, 4, 0x80)
795                         break;
796                 case BC_YUV161616:
797                         POLAR_MACRO(uint16_t, 0xffff, 3, 0x8000)
798                         break;
799                 case BC_YUVA16161616:
800                         POLAR_MACRO(uint16_t, 0xffff, 4, 0x8000)
801                         break;
802         }
808 PolarEngine::PolarEngine(PolarEffect *plugin, int cpus)
809  : LoadServer(cpus, cpus)
811         this->plugin = plugin;
814 void PolarEngine::init_packages()
816         for(int i = 0; i < LoadServer::get_total_packages(); i++)
817         {
818                 PolarPackage *pkg = (PolarPackage*)get_package(i);
819                 pkg->row1 = plugin->input->get_h() * i / LoadServer::get_total_packages();
820                 pkg->row2 = plugin->input->get_h() * (i + 1) / LoadServer::get_total_packages();
821         }
824 LoadClient* PolarEngine::new_client()
826         return new PolarUnit(plugin, this);
829 LoadPackage* PolarEngine::new_package()
831         return new PolarPackage;