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