r125: This commit was manufactured by cvs2svn to create tag 'r1_1_7-last'.
[cinelerra_cv/mob.git] / hvirtual / plugins / polar / polar.C
blobfd1f72b5d8c5ae2523b9d308cf7bde2675ae4f43
1 #include "bcdisplayinfo.h"
2 #include "clip.h"
3 #include "defaults.h"
4 #include "filexml.h"
5 #include "guicast.h"
6 #include "keyframe.h"
7 #include "loadbalance.h"
8 #include "picon_png.h"
9 #include "pluginvclient.h"
10 #include "vframe.h"
14 #include <string.h>
15 #include <stdint.h>
17 #include <libintl.h>
18 #define _(String) gettext(String)
19 #define gettext_noop(String) String
20 #define N_(String) gettext_noop (String)
22 #define SQR(x) ((x) * (x))
23 #define WITHIN(a, b, c) ((((a) <= (b)) && ((b) <= (c))) ? 1 : 0)
26 class PolarEffect;
27 class PolarEngine;
28 class PolarWindow;
31 class PolarConfig
33 public:
34         PolarConfig();
36         void copy_from(PolarConfig &src);
37         int equivalent(PolarConfig &src);
38         void interpolate(PolarConfig &prev, 
39                 PolarConfig &next, 
40                 long prev_frame, 
41                 long next_frame, 
42                 long current_frame);
43         
44         int polar_to_rectangular;
45         float depth;
46         float angle;
47         int backwards;
48         int invert;
53 class PolarDepth : public BC_FSlider
55 public:
56         PolarDepth(PolarEffect *plugin, int x, int y);
57         int handle_event();
58         PolarEffect *plugin;
61 class PolarAngle : public BC_FSlider
63 public:
64         PolarAngle(PolarEffect *plugin, int x, int y);
65         int handle_event();
66         PolarEffect *plugin;
69 class PolarWindow : public BC_Window
71 public:
72         PolarWindow(PolarEffect *plugin, int x, int y);
73         void create_objects();
74         int close_event();
75         PolarEffect *plugin;
76         PolarDepth *depth;
77         PolarAngle *angle;
81 PLUGIN_THREAD_HEADER(PolarEffect, PolarThread, PolarWindow)
84 class PolarPackage : public LoadPackage
86 public:
87         PolarPackage();
88         int row1, row2;
91 class PolarUnit : public LoadClient
93 public:
94         PolarUnit(PolarEffect *plugin, PolarEngine *server);
95         void process_package(LoadPackage *package);
96         PolarEffect *plugin;
99 class PolarEngine : public LoadServer
101 public:
102         PolarEngine(PolarEffect *plugin, int cpus);
103         void init_packages();
104         LoadClient* new_client();
105         LoadPackage* new_package();
106         PolarEffect *plugin;
109 class PolarEffect : public PluginVClient
111 public:
112         PolarEffect(PluginServer *server);
113         ~PolarEffect();
115         int process_realtime(VFrame *input, VFrame *output);
116         int is_realtime();
117         char* plugin_title();
118         VFrame* new_picon();
119         int load_configuration();
120         int load_defaults();
121         int save_defaults();
122         void save_data(KeyFrame *keyframe);
123         void read_data(KeyFrame *keyframe);
124         int show_gui();
125         int set_string();
126         void raise_window();
127         void update_gui();
129         PolarConfig config;
130         Defaults *defaults;
131         PolarThread *thread;
132         PolarEngine *engine;
133         VFrame *temp_frame;
134         VFrame *input, *output;
135         int need_reconfigure;
140 REGISTER_PLUGIN(PolarEffect)
144 PolarConfig::PolarConfig()
146         angle = 0.0;
147         depth = 0.0;
148         backwards = 0;
149         invert = 0;
150         polar_to_rectangular = 1;
154 void PolarConfig::copy_from(PolarConfig &src)
156         this->angle = src.angle;
157         this->depth = src.depth;
158         this->backwards = src.backwards;
159         this->invert = src.invert;
160         this->polar_to_rectangular = src.polar_to_rectangular;
163 int PolarConfig::equivalent(PolarConfig &src)
165         return EQUIV(this->angle, src.angle) && EQUIV(this->depth, src.depth);
168 void PolarConfig::interpolate(PolarConfig &prev, 
169                 PolarConfig &next, 
170                 long prev_frame, 
171                 long next_frame, 
172                 long current_frame)
174         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
175         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
177         this->depth = prev.depth * prev_scale + next.depth * next_scale;
178         this->angle = prev.angle * prev_scale + next.angle * next_scale;
186 PolarWindow::PolarWindow(PolarEffect *plugin, int x, int y)
187  : BC_Window(plugin->gui_string, 
188         x, 
189         y, 
190         270, 
191         100, 
192         270, 
193         100, 
194         0, 
195         0,
196         1)
198         this->plugin = plugin;
201 void PolarWindow::create_objects()
203         int x = 10, y = 10;
204         add_subwindow(new BC_Title(x, y, _("Depth:")));
205         add_subwindow(depth = new PolarDepth(plugin, x + 50, y));
206         y += 40;
207         add_subwindow(new BC_Title(x, y, _("Angle:")));
208         add_subwindow(angle = new PolarAngle(plugin, x + 50, y));
210         show_window();
211         flush();
214 int PolarWindow::close_event()
216         set_done(1);
217         return 1;
220 PLUGIN_THREAD_OBJECT(PolarEffect, PolarThread, PolarWindow)
223 PolarDepth::PolarDepth(PolarEffect *plugin, int x, int y)
224  : BC_FSlider(x, 
225                 y, 
226                 0,
227                 200,
228                 200, 
229                 (float)1, 
230                 (float)100,
231                 plugin->config.depth)
233         this->plugin = plugin;
235 int PolarDepth::handle_event()
237         plugin->config.depth = get_value();
238         plugin->send_configure_change();
239         return 1;
246 PolarAngle::PolarAngle(PolarEffect *plugin, int x, int y)
247  : BC_FSlider(x, 
248                 y, 
249                 0,
250                 200,
251                 200, 
252                 (float)1, 
253                 (float)360, 
254                 plugin->config.angle)
256         this->plugin = plugin;
258 int PolarAngle::handle_event()
260         plugin->config.angle = get_value();
261         plugin->send_configure_change();
262         return 1;
269 PolarEffect::PolarEffect(PluginServer *server)
270  : PluginVClient(server)
272         need_reconfigure = 1;
273         temp_frame = 0;
274         engine = 0;
275         PLUGIN_CONSTRUCTOR_MACRO
278 PolarEffect::~PolarEffect()
280         PLUGIN_DESTRUCTOR_MACRO
281         if(temp_frame) delete temp_frame;
282         if(engine) delete engine;
286 int PolarEffect::is_realtime()
288         return 1;
291 char* PolarEffect::plugin_title()
293         return _("Polar");
296 NEW_PICON_MACRO(PolarEffect)
298 SHOW_GUI_MACRO(PolarEffect, PolarThread)
300 RAISE_WINDOW_MACRO(PolarEffect)
302 SET_STRING_MACRO(PolarEffect)
304 void PolarEffect::update_gui()
306         if(thread)
307         {
308                 load_configuration();
309                 thread->window->lock_window();
310                 thread->window->angle->update(config.angle);
311                 thread->window->depth->update(config.depth);
312                 thread->window->unlock_window();
313         }
316 LOAD_CONFIGURATION_MACRO(PolarEffect, PolarConfig)
319 int PolarEffect::load_defaults()
321         char directory[BCTEXTLEN];
322 // set the default directory
323         sprintf(directory, "%spolar.rc", BCASTDIR);
325 // load the defaults
326         defaults = new Defaults(directory);
327         defaults->load();
329         config.depth = defaults->get("DEPTH", config.depth);
330         config.angle = defaults->get("ANGLE", config.angle);
331         return 0;
334 int PolarEffect::save_defaults()
336         defaults->update("DEPTH", config.depth);
337         defaults->update("ANGLE", config.angle);
338         defaults->save();
339         return 0;
342 void PolarEffect::save_data(KeyFrame *keyframe)
344         FileXML output;
346 // cause data to be stored directly in text
347         output.set_shared_string(keyframe->data, MESSAGESIZE);
348         output.tag.set_title("POLAR");
349         output.tag.set_property("DEPTH", config.depth);
350         output.tag.set_property("ANGLE", config.angle);
351         output.append_tag();
352         output.terminate_string();
355 void PolarEffect::read_data(KeyFrame *keyframe)
357         FileXML input;
359         input.set_shared_string(keyframe->data, strlen(keyframe->data));
361         int result = 0;
363         while(!input.read_tag())
364         {
365                 if(input.tag.title_is("POLAR"))
366                 {
367                         config.depth = input.tag.get_property("DEPTH", config.depth);
368                         config.angle = input.tag.get_property("ANGLE", config.angle);
369                 }
370         }
373 int PolarEffect::process_realtime(VFrame *input, VFrame *output)
375         need_reconfigure |= load_configuration();
377         this->input = input;
378         this->output = output;
380         if(EQUIV(config.depth, 0) || EQUIV(config.angle, 0))
381         {
382                 if(input->get_rows()[0] != output->get_rows()[0])
383                         output->copy_from(input);
384         }
385         else
386         {
387                 if(input->get_rows()[0] == output->get_rows()[0])
388                 {
389                         if(!temp_frame) temp_frame = new VFrame(0,
390                                 input->get_w(),
391                                 input->get_h(),
392                                 input->get_color_model());
393                         temp_frame->copy_from(input);
394                         this->input = temp_frame;
395                 }
396                 
397                 
398                 if(!engine) engine = new PolarEngine(this, PluginClient::smp + 1);
400                 engine->process_packages();
401         }
402         return 0;
409 PolarPackage::PolarPackage()
410  : LoadPackage()
417 PolarUnit::PolarUnit(PolarEffect *plugin, PolarEngine *server)
418  : LoadClient(server)
420         this->plugin = plugin;
424 static int calc_undistorted_coords(int wx,
425                          int wy,
426                          int w,
427                          int h,
428                          float depth,
429                          double angle,
430                          int polar_to_rectangular,
431                          int backwards,
432                          int inverse,
433                          double cen_x,
434                          double cen_y,
435                          double &x,
436                          double &y)
438         int inside;
439         double phi, phi2;
440         double xx, xm, ym, yy;
441         int xdiff, ydiff;
442         double r;
443         double m;
444         double xmax, ymax, rmax;
445         double x_calc, y_calc;
446         double xi, yi;
447         double circle, angl, t;
448         int x1, x2, y1, y2;
450 /* initialize */
452         phi = 0.0;
453         r = 0.0;
455         x1 = 0;
456         y1 = 0;
457         x2 = w;
458         y2 = h;
459         xdiff = x2 - x1;
460         ydiff = y2 - y1;
461         xm = xdiff / 2.0;
462         ym = ydiff / 2.0;
463         circle = depth;
464         angle = angle;
465         angl = (double)angle / 180.0 * M_PI;
467     if(polar_to_rectangular)
468     {
469         if(wx >= cen_x)
470                 {
471                         if(wy > cen_y)
472                 {
473                         phi = M_PI - 
474                                         atan(((double)(wx - cen_x)) / 
475                                         ((double)(wy - cen_y)));
476                         r   = sqrt(SQR(wx - cen_x) + 
477                                         SQR(wy - cen_y));
478                 }
479                         else 
480                         if(wy < cen_y)
481                 {
482                         phi = atan(((double)(wx - cen_x)) / 
483                                         ((double)(cen_y - wy)));
484                         r   = sqrt(SQR(wx - cen_x) + 
485                                         SQR(cen_y - wy));
486                 }
487                         else
488                 {
489                         phi = M_PI / 2;
490                         r   = wx - cen_x;
491                 }
492                 }
493         else 
494                 if(wx < cen_x)
495                 {
496                         if(wy < cen_y)
497                 {
498                         phi = 2 * M_PI - 
499                                         atan(((double)(cen_x -wx)) /
500                                     ((double)(cen_y - wy)));
501                         r   = sqrt(SQR(cen_x - wx) + 
502                                         SQR(cen_y - wy));
503                 }
504                         else 
505                         if(wy > cen_y)
506                 {
507                         phi = M_PI + 
508                                         atan(((double)(cen_x - wx)) / 
509                                         ((double)(wy - cen_y)));
510                         r   = sqrt(SQR(cen_x - wx) + 
511                                         SQR(wy - cen_y));
512                 }
513                         else
514                 {
515                         phi = 1.5 * M_PI;
516                         r   = cen_x - wx;
517                 }
518                 }
519         if (wx != cen_x)
520                 {
521                         m = fabs(((double)(wy - cen_y)) / 
522                                 ((double)(wx - cen_x)));
523                 }
524         else
525                 {
526                     m = 0;
527                 }
528     
529         if(m <= ((double)(y2 - y1) / 
530                         (double)(x2 - x1)))
531                 {
532                         if(wx == cen_x)
533                 {
534                         xmax = 0;
535                         ymax = cen_y - y1;
536                 }
537                         else
538                 {
539                         xmax = cen_x - x1;
540                         ymax = m * xmax;
541                 }
542                 }
543         else
544                 {
545                         ymax = cen_y - y1;
546                         xmax = ymax / m;
547                 }
548     
549         rmax = sqrt((double)(SQR(xmax) + SQR(ymax)));
551         t = ((cen_y - y1) < (cen_x - x1)) ? (cen_y - y1) : (cen_x - x1);
552         rmax = (rmax - t) / 100 * (100 - circle) + t;
554         phi = fmod(phi + angl, 2 * M_PI);
556         if(backwards)
557                         x_calc = x2 - 1 - (x2 - x1 - 1) / (2 * M_PI) * phi;
558         else
559                         x_calc = (x2 - x1 - 1) / (2 * M_PI) * phi + x1;
561         if(inverse)
562                         y_calc = (y2 - y1) / rmax * r + y1;
563         else
564                         y_calc = y2 - (y2 - y1) / rmax * r;
566         xi = (int)(x_calc + 0.5);
567         yi = (int)(y_calc + 0.5);
568     
569         if(WITHIN(0, xi, w - 1) && WITHIN(0, yi, h - 1))
570                 {
571                         x = x_calc;
572                         y = y_calc;
574                         inside = 1;
575                 }
576         else
577                 {
578                         inside = 0;
579                 }
580     }
581         else
582     {
583         if(backwards)
584                         phi = (2 * M_PI) * (x2 - wx) / xdiff;
585         else
586                         phi = (2 * M_PI) * (wx - x1) / xdiff;
588         phi = fmod (phi + angl, 2 * M_PI);
589     
590         if(phi >= 1.5 * M_PI)
591                         phi2 = 2 * M_PI - phi;
592         else
593                 if (phi >= M_PI)
594                         phi2 = phi - M_PI;
595                 else
596                 if(phi >= 0.5 * M_PI)
597                 phi2 = M_PI - phi;
598                 else
599                 phi2 = phi;
601         xx = tan (phi2);
602         if(xx != 0)
603                         m = (double)1.0 / xx;
604         else
605                         m = 0;
606     
607         if(m <= ((double)(ydiff) / (double)(xdiff)))
608                 {
609                         if(phi2 == 0)
610                 {
611                         xmax = 0;
612                         ymax = ym - y1;
613                 }
614                         else
615                 {
616                         xmax = xm - x1;
617                         ymax = m * xmax;
618                 }
619                 }
620         else
621                 {
622                         ymax = ym - y1;
623                         xmax = ymax / m;
624                 }
625     
626         rmax = sqrt((double)(SQR(xmax) + SQR(ymax)));
627     
628         t = ((ym - y1) < (xm - x1)) ? (ym - y1) : (xm - x1);
630         rmax = (rmax - t) / 100.0 * (100 - circle) + t;
632         if(inverse)
633                         r = rmax * (double)((wy - y1) / (double)(ydiff));
634         else
635                         r = rmax * (double)((y2 - wy) / (double)(ydiff));
636     
637         xx = r * sin (phi2);
638         yy = r * cos (phi2);
640         if(phi >= 1.5 * M_PI)
641                 {
642                         x_calc = (double)xm - xx;
643                         y_calc = (double)ym - yy;
644                 }
645         else
646                 if(phi >= M_PI)
647                 {
648                 x_calc = (double)xm - xx;
649                 y_calc = (double)ym + yy;
650                 }
651                 else
652                 if(phi >= 0.5 * M_PI)
653             {
654                 x_calc = (double)xm + xx;
655                 y_calc = (double)ym + yy;
656             }
657                 else
658             {
659                 x_calc = (double)xm + xx;
660                 y_calc = (double)ym - yy;
661             }
663         xi = (int)(x_calc + 0.5);
664         yi = (int)(y_calc + 0.5);
665   
666         if(WITHIN(0, xi, w - 1) && 
667                         WITHIN(0, yi, h - 1)) 
668                 {
669                         x = x_calc;
670                         y = y_calc;
672                         inside = 1;
673         }
674         else
675                 {
676                         inside = 0;
677                 }
678     }
680         return inside;
683 static double bilinear(double x, double y, double *values)
685         double m0, m1;
686         x = fmod(x, 1.0);
687         y = fmod(y, 1.0);
689         if(x < 0.0) x += 1.0;
690         if(y < 0.0) y += 1.0;
692         m0 = values[0] + x * (values[1] - values[0]);
693         m1 = values[2] + x * (values[3] - values[2]);
694         return m0 + y * (m1 - m0);
697 #define GET_PIXEL(x, y, components, input_rows) \
698         input_rows[CLIP((y), 0, ((h) - 1))] + components * CLIP((x), 0, ((w) - 1))
700 #define POLAR_MACRO(type, max, components, chroma_offset) \
701 { \
702         type **in_rows = (type**)plugin->input->get_rows(); \
703         type **out_rows = (type**)plugin->output->get_rows(); \
704         double values[4]; \
706         for(int y = pkg->row1; y < pkg->row2; y++) \
707         { \
708                 type *output_row = out_rows[y]; \
710                 for(int x = 0; x < w; x++) \
711                 { \
712                         type *output_pixel = output_row + x * components; \
713                         if(calc_undistorted_coords(x, \
714                                 y, \
715                                 w, \
716                                 h, \
717                                 plugin->config.depth, \
718                                 plugin->config.angle, \
719                                 plugin->config.polar_to_rectangular, \
720                                 plugin->config.backwards, \
721                                 plugin->config.invert, \
722                                 cen_x, \
723                                 cen_y, \
724                                 cx, \
725                                 cy)) \
726                         { \
727                                 type *pixel1 = GET_PIXEL((int)cx,     (int)cy,   components, in_rows); \
728                                 type *pixel2 = GET_PIXEL((int)cx + 1, (int)cy,   components, in_rows); \
729                                 type *pixel3 = GET_PIXEL((int)cx,     (int)cy + 1, components, in_rows); \
730                                 type *pixel4 = GET_PIXEL((int)cx + 1, (int)cy + 1, components, in_rows); \
732                                 values[0] = pixel1[0]; \
733                                 values[1] = pixel2[0]; \
734                                 values[2] = pixel3[0]; \
735                                 values[3] = pixel4[0]; \
736                                 output_pixel[0] = (type)bilinear(cx, cy, values); \
738                                 values[0] = pixel1[1]; \
739                                 values[1] = pixel2[1]; \
740                                 values[2] = pixel3[1]; \
741                                 values[3] = pixel4[1]; \
742                                 output_pixel[1] = (type)bilinear(cx, cy, values); \
744                                 values[0] = pixel1[2]; \
745                                 values[1] = pixel2[2]; \
746                                 values[2] = pixel3[2]; \
747                                 values[3] = pixel4[2]; \
748                                 output_pixel[2] = (type)bilinear(cx, cy, values); \
750                                 if(components == 4) \
751                                 { \
752                                         values[0] = pixel1[3]; \
753                                         values[1] = pixel2[3]; \
754                                         values[2] = pixel3[3]; \
755                                         values[3] = pixel4[3]; \
756                                         output_pixel[3] = (type)bilinear(cx, cy, values); \
757                                 } \
758                         } \
759                         else \
760                         { \
761                                 output_pixel[0] = 0; \
762                                 output_pixel[1] = chroma_offset; \
763                                 output_pixel[2] = chroma_offset; \
764                                 if(components == 4) output_pixel[3] = max; \
765                         } \
766                 } \
767         } \
771 void PolarUnit::process_package(LoadPackage *package)
773         PolarPackage *pkg = (PolarPackage*)package;
774         int w = plugin->input->get_w();
775         int h = plugin->input->get_h();
776         double cx;
777         double cy;
778         double cen_x = (double)(w - 1) / 2.0;
779         double cen_y = (double)(h - 1) / 2.0;
780         
781         switch(plugin->input->get_color_model())
782         {
783                 case BC_RGB888:
784                         POLAR_MACRO(unsigned char, 0xff, 3, 0x0)
785                         break;
786                 case BC_RGBA8888:
787                         POLAR_MACRO(unsigned char, 0xff, 4, 0x0)
788                         break;
789                 case BC_RGB161616:
790                         POLAR_MACRO(uint16_t, 0xffff, 3, 0x0)
791                         break;
792                 case BC_RGBA16161616:
793                         POLAR_MACRO(uint16_t, 0xffff, 4, 0x0)
794                         break;
795                 case BC_YUV888:
796                         POLAR_MACRO(unsigned char, 0xff, 3, 0x80)
797                         break;
798                 case BC_YUVA8888:
799                         POLAR_MACRO(unsigned char, 0xff, 4, 0x80)
800                         break;
801                 case BC_YUV161616:
802                         POLAR_MACRO(uint16_t, 0xffff, 3, 0x8000)
803                         break;
804                 case BC_YUVA16161616:
805                         POLAR_MACRO(uint16_t, 0xffff, 4, 0x8000)
806                         break;
807         }
813 PolarEngine::PolarEngine(PolarEffect *plugin, int cpus)
814  : LoadServer(cpus, cpus)
816         this->plugin = plugin;
819 void PolarEngine::init_packages()
821         int increment = plugin->input->get_h() / LoadServer::total_packages + 1;
822         int y = 0;
823         for(int i = 0; i < LoadServer::total_packages; i++)
824         {
825                 PolarPackage *pkg = (PolarPackage*)packages[i];
826                 pkg->row1 = y;
827                 pkg->row2 = y + increment;
828                 y += increment;
829                 if(pkg->row2 > plugin->input->get_h())
830                 {
831                         y = pkg->row2 = plugin->input->get_h();
832                 }
833         }
836 LoadClient* PolarEngine::new_client()
838         return new PolarUnit(plugin, this);
841 LoadPackage* PolarEngine::new_package()
843         return new PolarPackage;