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