7524a9fd1a027834b923c78670e957f5a857a180
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / radialblur / radialblur.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
23 #include "radialblur.h"
24
25
26
27 REGISTER_PLUGIN(RadialBlurMain)
28
29
30
31 RadialBlurConfig::RadialBlurConfig()
32 {
33         reset(RESET_DEFAULT_SETTINGS);
34 }
35
36
37 void RadialBlurConfig::reset(int clear)
38 {
39         switch(clear) {
40                 case RESET_ALL :
41                         x = xS(50);
42                         y = yS(50);
43                         angle = 0;
44                         steps = 1;
45                         r = 1;
46                         g = 1;
47                         b = 1;
48                         a = 1;
49                         break;
50                 case RESET_XSLIDER : x = xS(50);
51                         break;
52                 case RESET_YSLIDER : y = yS(50);
53                         break;
54                 case RESET_ANGLE : angle = 0;
55                         break;
56                 case RESET_STEPS : steps = 1;
57                         break;
58                 case RESET_DEFAULT_SETTINGS :
59                 default:
60                         x = xS(50);
61                         y = yS(50);
62                         angle = 33;
63                         steps = 10;
64                         r = 1;
65                         g = 1;
66                         b = 1;
67                         a = 1;
68                         break;
69         }
70 }
71
72 int RadialBlurConfig::equivalent(RadialBlurConfig &that)
73 {
74         return
75                 angle == that.angle &&
76                 x == that.x &&
77                 y == that.y &&
78                 steps == that.steps &&
79                 r == that.r &&
80                 g == that.g &&
81                 b == that.b &&
82                 a == that.a;
83 }
84
85 void RadialBlurConfig::copy_from(RadialBlurConfig &that)
86 {
87         x = that.x;
88         y = that.y;
89         angle = that.angle;
90         steps = that.steps;
91         r = that.r;
92         g = that.g;
93         b = that.b;
94         a = that.a;
95 }
96
97 void RadialBlurConfig::interpolate(RadialBlurConfig &prev,
98         RadialBlurConfig &next,
99         long prev_frame,
100         long next_frame,
101         long current_frame)
102 {
103         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
104         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
105         this->x = (int)(prev.x * prev_scale + next.x * next_scale + 0.5);
106         this->y = (int)(prev.y * prev_scale + next.y * next_scale + 0.5);
107         this->steps = (int)(prev.steps * prev_scale + next.steps * next_scale + 0.5);
108         this->angle = (int)(prev.angle * prev_scale + next.angle * next_scale + 0.5);
109         r = prev.r;
110         g = prev.g;
111         b = prev.b;
112         a = prev.a;
113 }
114
115
116
117
118
119
120
121
122
123
124
125
126
127 RadialBlurWindow::RadialBlurWindow(RadialBlurMain *plugin)
128  : PluginClientWindow(plugin,
129         xS(250),
130         yS(380),
131         xS(250),
132         yS(380),
133         0)
134 {
135         this->plugin = plugin;
136 }
137
138 RadialBlurWindow::~RadialBlurWindow()
139 {
140 }
141
142 void RadialBlurWindow::create_objects()
143 {
144         int xs10 = xS(10), xs50 = xS(50), xs100 = xS(100);
145         int ys10 = yS(10), ys20 = yS(20), ys30 = yS(30), ys40 = yS(45);
146         int x = xs10, y = ys10;
147         int x1 = 0; int clrBtn_w = xs50;
148         int defaultBtn_w = xs100;
149
150         add_subwindow(new BC_Title(x, y, _("X:")));
151         y += ys20;
152         add_subwindow(this->x = new RadialBlurSize(plugin, x, y, &plugin->config.x, 0, 100));
153         x1 = x + this->x->get_w() + xs10;
154         add_subwindow(xClr = new RadialBlurSliderClr(plugin, this, x1, y, clrBtn_w, RESET_XSLIDER));
155
156         y += ys30;
157         add_subwindow(new BC_Title(x, y, _("Y:")));
158         y += ys20;
159         add_subwindow(this->y = new RadialBlurSize(plugin, x, y, &plugin->config.y, 0, 100));
160         add_subwindow(yClr = new RadialBlurSliderClr(plugin, this, x1, y, clrBtn_w, RESET_YSLIDER));
161
162         y += ys30;
163         add_subwindow(new BC_Title(x, y, _("Angle:")));
164         y += ys20;
165         add_subwindow(angle = new RadialBlurSize(plugin, x, y, &plugin->config.angle, 0, 360));
166         add_subwindow(angleClr = new RadialBlurSliderClr(plugin, this, x1, y, clrBtn_w, RESET_ANGLE));
167
168         y += ys30;
169         add_subwindow(new BC_Title(x, y, _("Steps:")));
170         y += ys20;
171         add_subwindow(steps = new RadialBlurSize(plugin, x, y, &plugin->config.steps, 1, 100));
172         add_subwindow(stepsClr = new RadialBlurSliderClr(plugin, this, x1, y, clrBtn_w, RESET_STEPS));
173
174         y += ys30;
175         add_subwindow(r = new RadialBlurToggle(plugin, x, y, &plugin->config.r, _("Red")));
176         y += ys30;
177         add_subwindow(g = new RadialBlurToggle(plugin, x, y, &plugin->config.g, _("Green")));
178         y += ys30;
179         add_subwindow(b = new RadialBlurToggle(plugin, x, y, &plugin->config.b, _("Blue")));
180         y += ys30;
181         add_subwindow(a = new RadialBlurToggle(plugin, x, y, &plugin->config.a, _("Alpha")));
182         y += ys40;
183         add_subwindow(reset = new RadialBlurReset(plugin, this, x, y));
184         add_subwindow(default_settings = new RadialBlurDefaultSettings(plugin, this,
185                 (xS(250) - xS(10) - defaultBtn_w), y, defaultBtn_w));
186
187         show_window();
188         flush();
189 }
190
191 // for Reset button
192 void RadialBlurWindow::update_gui(int clear)
193 {
194         switch(clear) {
195                 case RESET_XSLIDER : this->x->update(plugin->config.x);
196                         break;
197                 case RESET_YSLIDER : this->y->update(plugin->config.y);
198                         break;
199                 case RESET_ANGLE : angle->update(plugin->config.angle);
200                         break;
201                 case RESET_STEPS : steps->update(plugin->config.steps);
202                         break;
203                 case RESET_ALL :
204                 case RESET_DEFAULT_SETTINGS :
205                 default:
206                         this->x->update(plugin->config.x);
207                         this->y->update(plugin->config.y);
208                         angle->update(plugin->config.angle);
209                         steps->update(plugin->config.steps);
210                         r->update(plugin->config.r);
211                         g->update(plugin->config.g);
212                         b->update(plugin->config.b);
213                         a->update(plugin->config.a);
214                         break;
215         }
216 }
217
218
219
220
221
222
223
224
225
226 RadialBlurToggle::RadialBlurToggle(RadialBlurMain *plugin,
227         int x,
228         int y,
229         int *output,
230         char *string)
231  : BC_CheckBox(x, y, *output, string)
232 {
233         this->plugin = plugin;
234         this->output = output;
235 }
236
237 int RadialBlurToggle::handle_event()
238 {
239         *output = get_value();
240         plugin->send_configure_change();
241         return 1;
242 }
243
244
245
246
247
248
249
250 RadialBlurSize::RadialBlurSize(RadialBlurMain *plugin,
251         int x,
252         int y,
253         int *output,
254         int min,
255         int max)
256  : BC_ISlider(x, y, 0, xS(200), yS(200), min, max, *output)
257 {
258         this->plugin = plugin;
259         this->output = output;
260 }
261 int RadialBlurSize::handle_event()
262 {
263         *output = get_value();
264         plugin->send_configure_change();
265         return 1;
266 }
267
268
269
270
271
272
273
274 RadialBlurReset::RadialBlurReset(RadialBlurMain *plugin, RadialBlurWindow *gui, int x, int y)
275  : BC_GenericButton(x, y, _("Reset"))
276 {
277         this->plugin = plugin;
278         this->gui = gui;
279 }
280 RadialBlurReset::~RadialBlurReset()
281 {
282 }
283 int RadialBlurReset::handle_event()
284 {
285         plugin->config.reset(RESET_ALL);
286         gui->update_gui(RESET_ALL);
287         plugin->send_configure_change();
288         return 1;
289 }
290
291
292 RadialBlurDefaultSettings::RadialBlurDefaultSettings(RadialBlurMain *plugin, RadialBlurWindow *gui, int x, int y, int w)
293  : BC_GenericButton(x, y, w, _("Default"))
294 {
295         this->plugin = plugin;
296         this->gui = gui;
297 }
298 RadialBlurDefaultSettings::~RadialBlurDefaultSettings()
299 {
300 }
301 int RadialBlurDefaultSettings::handle_event()
302 {
303         plugin->config.reset(RESET_DEFAULT_SETTINGS);
304         gui->update_gui(RESET_DEFAULT_SETTINGS);
305         plugin->send_configure_change();
306         return 1;
307 }
308
309
310 RadialBlurSliderClr::RadialBlurSliderClr(RadialBlurMain *plugin, RadialBlurWindow *gui, int x, int y, int w, int clear)
311  : BC_Button(x, y, w, plugin->get_theme()->get_image_set("reset_button"))
312 {
313         this->plugin = plugin;
314         this->gui = gui;
315         this->clear = clear;
316 }
317 RadialBlurSliderClr::~RadialBlurSliderClr()
318 {
319 }
320 int RadialBlurSliderClr::handle_event()
321 {
322         // clear==1 ==> X slider
323         // clear==2 ==> Y slider
324         // clear==3 ==> Angle slider
325         // clear==4 ==> Steps slider
326         plugin->config.reset(clear);
327         gui->update_gui(clear);
328         plugin->send_configure_change();
329         return 1;
330 }
331
332
333
334
335 RadialBlurMain::RadialBlurMain(PluginServer *server)
336  : PluginVClient(server)
337 {
338
339         engine = 0;
340         temp = 0;
341         rotate = 0;
342 }
343
344 RadialBlurMain::~RadialBlurMain()
345 {
346
347         if(engine) delete engine;
348         if(temp) delete temp;
349         delete rotate;
350 }
351
352 const char* RadialBlurMain::plugin_title() { return N_("Radial Blur"); }
353 int RadialBlurMain::is_realtime() { return 1; }
354
355
356
357 NEW_WINDOW_MACRO(RadialBlurMain, RadialBlurWindow)
358
359 LOAD_CONFIGURATION_MACRO(RadialBlurMain, RadialBlurConfig)
360
361 int RadialBlurMain::process_buffer(VFrame *frame,
362                                                         int64_t start_position,
363                                                         double frame_rate)
364 {
365         load_configuration();
366
367
368         read_frame(frame,
369                 0,
370                 get_source_position(),
371                 get_framerate(),
372 //              0);
373                 get_use_opengl());
374
375         if(get_use_opengl()) return run_opengl();
376
377         if(!engine) engine = new RadialBlurEngine(this,
378                 get_project_smp() + 1,
379                 get_project_smp() + 1);
380
381         this->input = frame;
382         this->output = frame;
383
384
385         if(!temp)
386                 temp = new VFrame(frame->get_w(), frame->get_h(),
387                         frame->get_color_model(), 0);
388         temp->copy_from(frame);
389         this->input = temp;
390
391         engine->process_packages();
392         return 0;
393 }
394
395
396 void RadialBlurMain::update_gui()
397 {
398         if(thread)
399         {
400                 load_configuration();
401                 thread->window->lock_window();
402                 ((RadialBlurWindow*)thread->window)->x->update(config.x);
403                 ((RadialBlurWindow*)thread->window)->y->update(config.y);
404                 ((RadialBlurWindow*)thread->window)->angle->update(config.angle);
405                 ((RadialBlurWindow*)thread->window)->steps->update(config.steps);
406                 ((RadialBlurWindow*)thread->window)->r->update(config.r);
407                 ((RadialBlurWindow*)thread->window)->g->update(config.g);
408                 ((RadialBlurWindow*)thread->window)->b->update(config.b);
409                 ((RadialBlurWindow*)thread->window)->a->update(config.a);
410                 thread->window->unlock_window();
411         }
412 }
413
414
415
416
417 void RadialBlurMain::save_data(KeyFrame *keyframe)
418 {
419         FileXML output;
420
421 // cause data to be stored directly in text
422         output.set_shared_output(keyframe->xbuf);
423         output.tag.set_title("RADIALBLUR");
424
425         output.tag.set_property("X", config.x);
426         output.tag.set_property("Y", config.y);
427         output.tag.set_property("ANGLE", config.angle);
428         output.tag.set_property("STEPS", config.steps);
429         output.tag.set_property("R", config.r);
430         output.tag.set_property("G", config.g);
431         output.tag.set_property("B", config.b);
432         output.tag.set_property("A", config.a);
433         output.append_tag();
434         output.tag.set_title("/RADIALBLUR");
435         output.append_tag();
436         output.append_newline();
437         output.terminate_string();
438 }
439
440 void RadialBlurMain::read_data(KeyFrame *keyframe)
441 {
442         FileXML input;
443
444         input.set_shared_input(keyframe->xbuf);
445
446         int result = 0;
447
448         while(!result)
449         {
450                 result = input.read_tag();
451
452                 if(!result)
453                 {
454                         if(input.tag.title_is("RADIALBLUR"))
455                         {
456                                 config.x = input.tag.get_property("X", config.x);
457                                 config.y = input.tag.get_property("Y", config.y);
458                                 config.angle = input.tag.get_property("ANGLE", config.angle);
459                                 config.steps = input.tag.get_property("STEPS", config.steps);
460                                 config.r = input.tag.get_property("R", config.r);
461                                 config.g = input.tag.get_property("G", config.g);
462                                 config.b = input.tag.get_property("B", config.b);
463                                 config.a = input.tag.get_property("A", config.a);
464                         }
465                 }
466         }
467 }
468
469 int RadialBlurMain::handle_opengl()
470 {
471 #ifdef HAVE_GL
472         get_output()->to_texture();
473         get_output()->enable_opengl();
474         get_output()->init_screen();
475         get_output()->bind_texture(0);
476
477
478         //int is_yuv = BC_CModels::is_yuv(get_output()->get_color_model());
479         glClearColor(0.0, 0.0, 0.0, 0.0);
480         glClear(GL_COLOR_BUFFER_BIT);
481
482 // Draw unselected channels
483         glEnable(GL_BLEND);
484         glBlendFunc(GL_ONE, GL_ONE);
485         glDrawBuffer(GL_BACK);
486         if(!config.r || !config.g || !config.b || !config.a)
487         {
488                 glColor4f(config.r ? 0 : 1,
489                         config.g ? 0 : 1,
490                         config.b ? 0 : 1,
491                         config.a ? 0 : 1);
492                 get_output()->draw_texture();
493         }
494         glAccum(GL_LOAD, 1.0);
495
496
497 // Blur selected channels
498         float fraction = 1.0 / config.steps;
499         for(int i = 0; i < config.steps; i++)
500         {
501                 get_output()->set_opengl_state(VFrame::TEXTURE);
502                 glClear(GL_COLOR_BUFFER_BIT);
503                 glColor4f(config.r ? 1 : 0,
504                         config.g ? 1 : 0,
505                         config.b ? 1 : 0,
506                         config.a ? 1 : 0);
507
508                 float w = get_output()->get_w();
509                 float h = get_output()->get_h();
510
511
512
513                 double current_angle = (double)config.angle *
514                         i /
515                         config.steps -
516                         (double)config.angle / 2;
517
518                 if(!rotate) rotate = new AffineEngine(PluginClient::smp + 1,
519                         PluginClient::smp + 1);
520                 rotate->set_in_pivot((int)(config.x * w / 100),
521                         (int)(config.y * h / 100));
522                 rotate->set_out_pivot((int)(config.x * w / 100),
523                         (int)(config.y * h / 100));
524                 rotate->set_opengl(1);
525                 rotate->rotate(get_output(),
526                         get_output(),
527                         current_angle);
528
529                 glAccum(GL_ACCUM, fraction);
530                 glEnable(GL_TEXTURE_2D);
531                 glColor4f(config.r ? 1 : 0,
532                         config.g ? 1 : 0,
533                         config.b ? 1 : 0,
534                         config.a ? 1 : 0);
535         }
536
537
538         glDisable(GL_BLEND);
539         glReadBuffer(GL_BACK);
540         glDisable(GL_TEXTURE_2D);
541         glAccum(GL_RETURN, 1.0);
542
543         glColor4f(1, 1, 1, 1);
544         get_output()->set_opengl_state(VFrame::SCREEN);
545 #endif
546         return 0;
547 }
548
549
550
551
552
553
554
555
556
557
558
559 RadialBlurPackage::RadialBlurPackage()
560  : LoadPackage()
561 {
562 }
563
564
565 RadialBlurUnit::RadialBlurUnit(RadialBlurEngine *server,
566         RadialBlurMain *plugin)
567  : LoadClient(server)
568 {
569         this->plugin = plugin;
570         this->server = server;
571 }
572
573
574 #define BLEND_LAYER(COMPONENTS, TYPE, TEMP_TYPE, MAX, DO_YUV) \
575 { \
576         int chroma_offset = (DO_YUV ? ((MAX + 1) / 2) : 0); \
577         TYPE **in_rows = (TYPE**)plugin->input->get_rows(); \
578         TYPE **out_rows = (TYPE**)plugin->output->get_rows(); \
579         int steps = plugin->config.steps; \
580         double step = (double)plugin->config.angle / 360 * 2 * M_PI / steps; \
581  \
582         for(int i = pkg->y1, out_y = pkg->y1 - center_y; \
583                 i < pkg->y2; \
584                 i++, out_y++) \
585         { \
586                 TYPE *out_row = out_rows[i]; \
587                 TYPE *in_row = in_rows[i]; \
588                 int y_square = out_y * out_y; \
589  \
590                 for(int j = 0, out_x = -center_x; j < w; j++, out_x++) \
591                 { \
592                         TEMP_TYPE accum_r = 0; \
593                         TEMP_TYPE accum_g = 0; \
594                         TEMP_TYPE accum_b = 0; \
595                         TEMP_TYPE accum_a = 0; \
596  \
597 /* Output coordinate to polar */ \
598                         double magnitude = sqrt(y_square + out_x * out_x); \
599                         double angle; \
600                         if(out_y < 0) \
601                                 angle = atan((double)out_x / out_y) + M_PI; \
602                         else \
603                         if(out_y > 0) \
604                                 angle = atan((double)out_x / out_y); \
605                         else \
606                         if(out_x > 0) \
607                                 angle = M_PI / 2; \
608                         else \
609                                 angle = M_PI * 1.5; \
610  \
611 /* Overlay all steps on this pixel*/ \
612                         angle -= (double)plugin->config.angle / 360 * M_PI; \
613                         for(int k = 0; k < steps; k++, angle += step) \
614                         { \
615 /* Polar to input coordinate */ \
616                                 int in_x = (int)(magnitude * sin(angle)) + center_x; \
617                                 int in_y = (int)(magnitude * cos(angle)) + center_y; \
618  \
619 /* Accumulate input coordinate */ \
620                                 if(in_x >= 0 && in_x < w && in_y >= 0 && in_y < h) \
621                                 { \
622                                         accum_r += in_rows[in_y][in_x * COMPONENTS]; \
623                                         if(DO_YUV) \
624                                         { \
625                                                 accum_g += (int)in_rows[in_y][in_x * COMPONENTS + 1]; \
626                                                 accum_b += (int)in_rows[in_y][in_x * COMPONENTS + 2]; \
627                                         } \
628                                         else \
629                                         { \
630                                                 accum_g += in_rows[in_y][in_x * COMPONENTS + 1]; \
631                                                 accum_b += in_rows[in_y][in_x * COMPONENTS + 2]; \
632                                         } \
633                                         if(COMPONENTS == 4) \
634                                                 accum_a += in_rows[in_y][in_x * COMPONENTS + 3]; \
635                                 } \
636                                 else \
637                                 { \
638                                         accum_g += chroma_offset; \
639                                         accum_b += chroma_offset; \
640                                 } \
641                         } \
642  \
643 /* Accumulation to output */ \
644                         if(do_r) \
645                         { \
646                                 *out_row++ = (accum_r * fraction) / 0x10000; \
647                                 in_row++; \
648                         } \
649                         else \
650                         { \
651                                 *out_row++ = *in_row++; \
652                         } \
653  \
654                         if(do_g) \
655                         { \
656                                 if(DO_YUV) \
657                                         *out_row++ = ((accum_g * fraction) / 0x10000); \
658                                 else \
659                                         *out_row++ = (accum_g * fraction) / 0x10000; \
660                                 in_row++; \
661                         } \
662                         else \
663                         { \
664                                 *out_row++ = *in_row++; \
665                         } \
666  \
667                         if(do_b) \
668                         { \
669                                 if(DO_YUV) \
670                                         *out_row++ = (accum_b * fraction) / 0x10000; \
671                                 else \
672                                         *out_row++ = (accum_b * fraction) / 0x10000; \
673                                 in_row++; \
674                         } \
675                         else \
676                         { \
677                                 *out_row++ = *in_row++; \
678                         } \
679  \
680                         if(COMPONENTS == 4) \
681                         { \
682                                 if(do_a) \
683                                 { \
684                                         *out_row++ = (accum_a * fraction) / 0x10000; \
685                                         in_row++; \
686                                 } \
687                                 else \
688                                 { \
689                                         *out_row++ = *in_row++; \
690                                 } \
691                         } \
692                 } \
693         } \
694 }
695
696 void RadialBlurUnit::process_package(LoadPackage *package)
697 {
698         RadialBlurPackage *pkg = (RadialBlurPackage*)package;
699         int h = plugin->output->get_h();
700         int w = plugin->output->get_w();
701         int do_r = plugin->config.r;
702         int do_g = plugin->config.g;
703         int do_b = plugin->config.b;
704         int do_a = plugin->config.a;
705         int fraction = 0x10000 / plugin->config.steps;
706         int center_x = plugin->config.x * w / 100;
707         int center_y = plugin->config.y * h / 100;
708
709         switch(plugin->input->get_color_model())
710         {
711                 case BC_RGB888:
712                         BLEND_LAYER(3, uint8_t, int, 0xff, 0)
713                         break;
714                 case BC_RGBA8888:
715                         BLEND_LAYER(4, uint8_t, int, 0xff, 0)
716                         break;
717                 case BC_RGB_FLOAT:
718                         BLEND_LAYER(3, float, float, 1, 0)
719                         break;
720                 case BC_RGBA_FLOAT:
721                         BLEND_LAYER(4, float, float, 1, 0)
722                         break;
723                 case BC_RGB161616:
724                         BLEND_LAYER(3, uint16_t, int, 0xffff, 0)
725                         break;
726                 case BC_RGBA16161616:
727                         BLEND_LAYER(4, uint16_t, int, 0xffff, 0)
728                         break;
729                 case BC_YUV888:
730                         BLEND_LAYER(3, uint8_t, int, 0xff, 1)
731                         break;
732                 case BC_YUVA8888:
733                         BLEND_LAYER(4, uint8_t, int, 0xff, 1)
734                         break;
735                 case BC_YUV161616:
736                         BLEND_LAYER(3, uint16_t, int, 0xffff, 1)
737                         break;
738                 case BC_YUVA16161616:
739                         BLEND_LAYER(4, uint16_t, int, 0xffff, 1)
740                         break;
741         }
742 }
743
744
745
746
747
748
749 RadialBlurEngine::RadialBlurEngine(RadialBlurMain *plugin,
750         int total_clients,
751         int total_packages)
752  : LoadServer(total_clients, total_packages)
753 // : LoadServer(1, 1)
754 {
755         this->plugin = plugin;
756 }
757
758 void RadialBlurEngine::init_packages()
759 {
760         for(int i = 0; i < get_total_packages(); i++)
761         {
762                 RadialBlurPackage *package = (RadialBlurPackage*)get_package(i);
763                 package->y1 = plugin->output->get_h() * i / get_total_packages();
764                 package->y2 = plugin->output->get_h() * (i + 1) / get_total_packages();
765         }
766 }
767
768 LoadClient* RadialBlurEngine::new_client()
769 {
770         return new RadialBlurUnit(this, plugin);
771 }
772
773 LoadPackage* RadialBlurEngine::new_package()
774 {
775         return new RadialBlurPackage;
776 }
777
778
779
780
781