Fixed initialisation of tf in file_open(). Without setting the memory to 0,
[cinelerra_cv/mob.git] / plugins / zoomblur / zoomblur.C
blobffba7399eb7321189c5e8215a414bf121a67ff03
1 #include <math.h>
2 #include <stdint.h>
3 #include <string.h>
5 #include "bcdisplayinfo.h"
6 #include "bcsignals.h"
7 #include "clip.h"
8 #include "bchash.h"
9 #include "filexml.h"
10 #include "keyframe.h"
11 #include "language.h"
12 #include "loadbalance.h"
13 #include "picon_png.h"
14 #include "pluginvclient.h"
15 #include "vframe.h"
19 class ZoomBlurMain;
20 class ZoomBlurEngine;
26 class ZoomBlurConfig
28 public:
29         ZoomBlurConfig();
31         int equivalent(ZoomBlurConfig &that);
32         void copy_from(ZoomBlurConfig &that);
33         void interpolate(ZoomBlurConfig &prev, 
34                 ZoomBlurConfig &next, 
35                 long prev_frame, 
36                 long next_frame, 
37                 long current_frame);
39         int x;
40         int y;
41         int radius;
42         int steps;
43         int r;
44         int g;
45         int b;
46         int a;
51 class ZoomBlurSize : public BC_ISlider
53 public:
54         ZoomBlurSize(ZoomBlurMain *plugin, 
55                 int x, 
56                 int y, 
57                 int *output,
58                 int min,
59                 int max);
60         int handle_event();
61         ZoomBlurMain *plugin;
62         int *output;
65 class ZoomBlurToggle : public BC_CheckBox
67 public:
68         ZoomBlurToggle(ZoomBlurMain *plugin, 
69                 int x, 
70                 int y, 
71                 int *output,
72                 char *string);
73         int handle_event();
74         ZoomBlurMain *plugin;
75         int *output;
78 class ZoomBlurWindow : public BC_Window
80 public:
81         ZoomBlurWindow(ZoomBlurMain *plugin, int x, int y);
82         ~ZoomBlurWindow();
84         int create_objects();
85         int close_event();
87         ZoomBlurSize *x, *y, *radius, *steps;
88         ZoomBlurToggle *r, *g, *b, *a;
89         ZoomBlurMain *plugin;
94 PLUGIN_THREAD_HEADER(ZoomBlurMain, ZoomBlurThread, ZoomBlurWindow)
97 // Output coords for a layer of blurring
98 // Used for OpenGL only
99 class ZoomBlurLayer
101 public:
102         ZoomBlurLayer() {};
103         float x1, y1, x2, y2;
106 class ZoomBlurMain : public PluginVClient
108 public:
109         ZoomBlurMain(PluginServer *server);
110         ~ZoomBlurMain();
112         int process_buffer(VFrame *frame,
113                 int64_t start_position,
114                 double frame_rate);
115         int is_realtime();
116         int load_defaults();
117         int save_defaults();
118         void save_data(KeyFrame *keyframe);
119         void read_data(KeyFrame *keyframe);
120         void update_gui();
121         int handle_opengl();
123         PLUGIN_CLASS_MEMBERS(ZoomBlurConfig, ZoomBlurThread)
125         void delete_tables();
126         VFrame *input, *output, *temp;
127         ZoomBlurEngine *engine;
128         int **scale_y_table;
129         int **scale_x_table;
130         ZoomBlurLayer *layer_table;
131         int table_entries;
132         int need_reconfigure;
133 // The accumulation buffer is needed because 8 bits isn't precise enough
134         unsigned char *accum;
137 class ZoomBlurPackage : public LoadPackage
139 public:
140         ZoomBlurPackage();
141         int y1, y2;
144 class ZoomBlurUnit : public LoadClient
146 public:
147         ZoomBlurUnit(ZoomBlurEngine *server, ZoomBlurMain *plugin);
148         void process_package(LoadPackage *package);
149         ZoomBlurEngine *server;
150         ZoomBlurMain *plugin;
153 class ZoomBlurEngine : public LoadServer
155 public:
156         ZoomBlurEngine(ZoomBlurMain *plugin, 
157                 int total_clients, 
158                 int total_packages);
159         void init_packages();
160         LoadClient* new_client();
161         LoadPackage* new_package();
162         ZoomBlurMain *plugin;
183 REGISTER_PLUGIN(ZoomBlurMain)
187 ZoomBlurConfig::ZoomBlurConfig()
189         x = 50;
190         y = 50;
191         radius = 10;
192         steps = 10;
193         r = 1;
194         g = 1;
195         b = 1;
196         a = 1;
199 int ZoomBlurConfig::equivalent(ZoomBlurConfig &that)
201         return 
202                 x == that.x &&
203                 y == that.y &&
204                 radius == that.radius &&
205                 steps == that.steps &&
206                 r == that.r &&
207                 g == that.g &&
208                 b == that.b &&
209                 a == that.a;
212 void ZoomBlurConfig::copy_from(ZoomBlurConfig &that)
214         x = that.x;
215         y = that.y;
216         radius = that.radius;
217         steps = that.steps;
218         r = that.r;
219         g = that.g;
220         b = that.b;
221         a = that.a;
224 void ZoomBlurConfig::interpolate(ZoomBlurConfig &prev, 
225         ZoomBlurConfig &next, 
226         long prev_frame, 
227         long next_frame, 
228         long current_frame)
230         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
231         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
232         this->x = (int)(prev.x * prev_scale + next.x * next_scale + 0.5);
233         this->y = (int)(prev.y * prev_scale + next.y * next_scale + 0.5);
234         this->radius = (int)(prev.radius * prev_scale + next.radius * next_scale + 0.5);
235         this->steps = (int)(prev.steps * prev_scale + next.steps * next_scale + 0.5);
236         r = prev.r;
237         g = prev.g;
238         b = prev.b;
239         a = prev.a;
250 PLUGIN_THREAD_OBJECT(ZoomBlurMain, ZoomBlurThread, ZoomBlurWindow)
254 ZoomBlurWindow::ZoomBlurWindow(ZoomBlurMain *plugin, int x, int y)
255  : BC_Window(plugin->gui_string, 
256         x,
257         y,
258         230, 
259         340, 
260         230, 
261         340, 
262         0, 
263         1)
265         this->plugin = plugin; 
268 ZoomBlurWindow::~ZoomBlurWindow()
272 int ZoomBlurWindow::create_objects()
274         int x = 10, y = 10;
276         add_subwindow(new BC_Title(x, y, _("X:")));
277         y += 20;
278         add_subwindow(this->x = new ZoomBlurSize(plugin, x, y, &plugin->config.x, 0, 100));
279         y += 30;
280         add_subwindow(new BC_Title(x, y, _("Y:")));
281         y += 20;
282         add_subwindow(this->y = new ZoomBlurSize(plugin, x, y, &plugin->config.y, 0, 100));
283         y += 30;
284         add_subwindow(new BC_Title(x, y, _("Radius:")));
285         y += 20;
286         add_subwindow(radius = new ZoomBlurSize(plugin, x, y, &plugin->config.radius, -100, 100));
287         y += 30;
288         add_subwindow(new BC_Title(x, y, _("Steps:")));
289         y += 20;
290         add_subwindow(steps = new ZoomBlurSize(plugin, x, y, &plugin->config.steps, 1, 100));
291         y += 30;
292         add_subwindow(r = new ZoomBlurToggle(plugin, x, y, &plugin->config.r, _("Red")));
293         y += 30;
294         add_subwindow(g = new ZoomBlurToggle(plugin, x, y, &plugin->config.g, _("Green")));
295         y += 30;
296         add_subwindow(b = new ZoomBlurToggle(plugin, x, y, &plugin->config.b, _("Blue")));
297         y += 30;
298         add_subwindow(a = new ZoomBlurToggle(plugin, x, y, &plugin->config.a, _("Alpha")));
299         y += 30;
301         show_window();
302         flush();
303         return 0;
306 int ZoomBlurWindow::close_event()
308 // Set result to 1 to indicate a plugin side close
309         set_done(1);
310         return 1;
322 ZoomBlurToggle::ZoomBlurToggle(ZoomBlurMain *plugin, 
323         int x, 
324         int y, 
325         int *output, 
326         char *string)
327  : BC_CheckBox(x, y, *output, string)
329         this->plugin = plugin;
330         this->output = output;
333 int ZoomBlurToggle::handle_event()
335         *output = get_value();
336         plugin->send_configure_change();
337         return 1;
346 ZoomBlurSize::ZoomBlurSize(ZoomBlurMain *plugin, 
347         int x, 
348         int y, 
349         int *output,
350         int min,
351         int max)
352  : BC_ISlider(x, y, 0, 200, 200, min, max, *output)
354         this->plugin = plugin;
355         this->output = output;
357 int ZoomBlurSize::handle_event()
359         *output = get_value();
360         plugin->send_configure_change();
361         return 1;
373 ZoomBlurMain::ZoomBlurMain(PluginServer *server)
374  : PluginVClient(server)
376         PLUGIN_CONSTRUCTOR_MACRO
377         engine = 0;
378         scale_x_table = 0;
379         scale_y_table = 0;
380         layer_table = 0;
381         table_entries = 0;
382         accum = 0;
383         need_reconfigure = 1;
384         temp = 0;
387 ZoomBlurMain::~ZoomBlurMain()
389         PLUGIN_DESTRUCTOR_MACRO
390         if(engine) delete engine;
391         delete_tables();
392         if(accum) delete [] accum;
393         if(temp) delete temp;
396 char* ZoomBlurMain::plugin_title() { return N_("Zoom Blur"); }
397 int ZoomBlurMain::is_realtime() { return 1; }
400 NEW_PICON_MACRO(ZoomBlurMain)
402 SHOW_GUI_MACRO(ZoomBlurMain, ZoomBlurThread)
404 SET_STRING_MACRO(ZoomBlurMain)
406 RAISE_WINDOW_MACRO(ZoomBlurMain)
408 LOAD_CONFIGURATION_MACRO(ZoomBlurMain, ZoomBlurConfig)
410 void ZoomBlurMain::delete_tables()
412         if(scale_x_table)
413         {
414                 for(int i = 0; i < table_entries; i++)
415                         delete [] scale_x_table[i];
416                 delete [] scale_x_table;
417         }
419         if(scale_y_table)
420         {
421                 for(int i = 0; i < table_entries; i++)
422                         delete [] scale_y_table[i];
423                 delete [] scale_y_table;
424         }
426         delete [] layer_table;
427         scale_x_table = 0;
428         scale_y_table = 0;
429         layer_table = 0;
430         table_entries = 0;
433 int ZoomBlurMain::process_buffer(VFrame *frame,
434                 int64_t start_position,
435                 double frame_rate)
437         need_reconfigure |= load_configuration();
440 SET_TRACE
441         read_frame(frame,
442                 0,
443                 get_source_position(),
444                 get_framerate(),
445                 get_use_opengl());
447 SET_TRACE
449 // Generate tables here.  The same table is used by many packages to render
450 // each horizontal stripe.  Need to cover the entire output range in  each
451 // table to avoid green borders
452         if(need_reconfigure)
453         {
454 SET_TRACE
455                 float w = frame->get_w();
456                 float h = frame->get_h();
457                 float center_x = (float)config.x / 100 * w;
458                 float center_y = (float)config.y / 100 * h;
459                 float radius = (float)(100 + config.radius) / 100;
460                 float min_w, min_h;
461                 float max_w, max_h;
462                 int steps = config.steps ? config.steps : 1;
463                 float min_x1;
464                 float min_y1;
465                 float min_x2;
466                 float min_y2;
467                 float max_x1;
468                 float max_y1;
469                 float max_x2;
470                 float max_y2;
471                 
472 SET_TRACE
474 // printf("ZoomBlurMain::process_realtime 1 %d %d\n", 
475 // config.x,
476 // config.y);
478                 center_x = (center_x - w / 2) * (1.0 - radius) + w / 2;
479                 center_y = (center_y - h / 2) * (1.0 - radius) + h / 2;
480                 min_w = w * radius;
481                 min_h = h * radius;
482                 max_w = w;
483                 max_h = h;
484                 min_x1 = center_x - min_w / 2;
485                 min_y1 = center_y - min_h / 2;
486                 min_x2 = center_x + min_w / 2;
487                 min_y2 = center_y + min_h / 2;
488                 max_x1 = 0;
489                 max_y1 = 0;
490                 max_x2 = w;
491                 max_y2 = h;
493 SET_TRACE
494 // printf("ZoomBlurMain::process_realtime 2 w=%f radius=%f center_x=%f\n", 
495 // w,
496 // radius,
497 // center_x);
500 // Dimensions of outermost rectangle
502                 delete_tables();
503                 table_entries = steps;
504                 scale_x_table = new int*[steps];
505                 scale_y_table = new int*[steps];
506                 layer_table = new ZoomBlurLayer[table_entries];
508 SET_TRACE
509                 for(int i = 0; i < steps; i++)
510                 {
511                         float fraction = (float)i / steps;
512                         float inv_fraction = 1.0 - fraction;
513                         float out_x1 = min_x1 * fraction + max_x1 * inv_fraction;
514                         float out_x2 = min_x2 * fraction + max_x2 * inv_fraction;
515                         float out_y1 = min_y1 * fraction + max_y1 * inv_fraction;
516                         float out_y2 = min_y2 * fraction + max_y2 * inv_fraction;
517                         float out_w = out_x2 - out_x1;
518                         float out_h = out_y2 - out_y1;
519                         if(out_w < 0) out_w = 0;
520                         if(out_h < 0) out_h = 0;
521                         float scale_x = (float)w / out_w;
522                         float scale_y = (float)h / out_h;
524                         int *x_table;
525                         int *y_table;
526                         scale_y_table[i] = y_table = new int[(int)(h + 1)];
527                         scale_x_table[i] = x_table = new int[(int)(w + 1)];
528 SET_TRACE
529                         layer_table[i].x1 = out_x1;
530                         layer_table[i].y1 = out_y1;
531                         layer_table[i].x2 = out_x2;
532                         layer_table[i].y2 = out_y2;
533 SET_TRACE
535                         for(int j = 0; j < h; j++)
536                         {
537                                 y_table[j] = (int)((j - out_y1) * scale_y);
538                         }
539                         for(int j = 0; j < w; j++)
540                         {
541                                 x_table[j] = (int)((j - out_x1) * scale_x);
542 //printf("ZoomBlurMain::process_realtime %d %d\n", j, x_table[j]);
543                         }
544                 }
545 SET_TRACE
546                 need_reconfigure = 0;
547         }
549 SET_TRACE
550         if(get_use_opengl()) return run_opengl();
552 SET_TRACE
556         if(!engine) engine = new ZoomBlurEngine(this,
557                 get_project_smp() + 1,
558                 get_project_smp() + 1);
559         if(!accum) accum = new unsigned char[frame->get_w() * 
560                 frame->get_h() *
561                 cmodel_components(frame->get_color_model()) *
562                 MAX(sizeof(int), sizeof(float))];
564         this->input = frame;
565         this->output = frame;
568         if(!temp) temp = new VFrame(0,
569                 frame->get_w(),
570                 frame->get_h(),
571                 frame->get_color_model());
572         temp->copy_from(frame);
573         this->input = temp;
575         bzero(accum, 
576                 frame->get_w() * 
577                 frame->get_h() *
578                 cmodel_components(frame->get_color_model()) *
579                 MAX(sizeof(int), sizeof(float)));
580         engine->process_packages();
581         return 0;
585 void ZoomBlurMain::update_gui()
587         if(thread)
588         {
589                 load_configuration();
590                 thread->window->lock_window();
591                 thread->window->x->update(config.x);
592                 thread->window->y->update(config.y);
593                 thread->window->radius->update(config.radius);
594                 thread->window->steps->update(config.steps);
595                 thread->window->r->update(config.r);
596                 thread->window->g->update(config.g);
597                 thread->window->b->update(config.b);
598                 thread->window->a->update(config.a);
599                 thread->window->unlock_window();
600         }
604 int ZoomBlurMain::load_defaults()
606         char directory[1024], string[1024];
607 // set the default directory
608         sprintf(directory, "%szoomblur.rc", BCASTDIR);
610 // load the defaults
611         defaults = new BC_Hash(directory);
612         defaults->load();
614         config.x = defaults->get("X", config.x);
615         config.y = defaults->get("Y", config.y);
616         config.radius = defaults->get("RADIUS", config.radius);
617         config.steps = defaults->get("STEPS", config.steps);
618         config.r = defaults->get("R", config.r);
619         config.g = defaults->get("G", config.g);
620         config.b = defaults->get("B", config.b);
621         config.a = defaults->get("A", config.a);
622         return 0;
626 int ZoomBlurMain::save_defaults()
628         defaults->update("X", config.x);
629         defaults->update("Y", config.y);
630         defaults->update("RADIUS", config.radius);
631         defaults->update("STEPS", config.steps);
632         defaults->update("R", config.r);
633         defaults->update("G", config.g);
634         defaults->update("B", config.b);
635         defaults->update("A", config.a);
636         defaults->save();
637         return 0;
642 void ZoomBlurMain::save_data(KeyFrame *keyframe)
644         FileXML output;
646 // cause data to be stored directly in text
647         output.set_shared_string(keyframe->data, MESSAGESIZE);
648         output.tag.set_title("ZOOMBLUR");
650         output.tag.set_property("X", config.x);
651         output.tag.set_property("Y", config.y);
652         output.tag.set_property("RADIUS", config.radius);
653         output.tag.set_property("STEPS", config.steps);
654         output.tag.set_property("R", config.r);
655         output.tag.set_property("G", config.g);
656         output.tag.set_property("B", config.b);
657         output.tag.set_property("A", config.a);
658         output.append_tag();
659         output.terminate_string();
662 void ZoomBlurMain::read_data(KeyFrame *keyframe)
664         FileXML input;
666         input.set_shared_string(keyframe->data, strlen(keyframe->data));
668         int result = 0;
670         while(!result)
671         {
672                 result = input.read_tag();
674                 if(!result)
675                 {
676                         if(input.tag.title_is("ZOOMBLUR"))
677                         {
678                                 config.x = input.tag.get_property("X", config.x);
679                                 config.y = input.tag.get_property("Y", config.y);
680                                 config.radius = input.tag.get_property("RADIUS", config.radius);
681                                 config.steps = input.tag.get_property("STEPS", config.steps);
682                                 config.r = input.tag.get_property("R", config.r);
683                                 config.g = input.tag.get_property("G", config.g);
684                                 config.b = input.tag.get_property("B", config.b);
685                                 config.a = input.tag.get_property("A", config.a);
686                         }
687                 }
688         }
691 #ifdef HAVE_GL
692 static void draw_box(float x1, float y1, float x2, float y2)
694         glBegin(GL_QUADS);
695         glVertex3f(x1, y1, 0.0);
696         glVertex3f(x2, y1, 0.0);
697         glVertex3f(x2, y2, 0.0);
698         glVertex3f(x1, y2, 0.0);
699         glEnd();
701 #endif
703 int ZoomBlurMain::handle_opengl()
705 #ifdef HAVE_GL
706         get_output()->to_texture();
707         get_output()->enable_opengl();
708         get_output()->init_screen();
709         get_output()->bind_texture(0);
711         int is_yuv = cmodel_is_yuv(get_output()->get_color_model());
712         glClearColor(0.0, 0.0, 0.0, 0.0);
713         glClear(GL_COLOR_BUFFER_BIT);
715 // Draw unselected channels
716         glEnable(GL_BLEND);
717         glBlendFunc(GL_ONE, GL_ONE);
718         glDrawBuffer(GL_BACK);
720         if(!config.r || !config.g || !config.b || !config.a)
721         {
722                 glColor4f(config.r ? 0 : 1, 
723                         config.g ? 0 : 1, 
724                         config.b ? 0 : 1, 
725                         config.a ? 0 : 1);
726                 get_output()->draw_texture();
727         }
728         glAccum(GL_LOAD, 1.0);
730 // Blur selected channels
731         float fraction = 1.0 / config.steps;
732         for(int i = 0; i < config.steps; i++)
733         {
734                 glClear(GL_COLOR_BUFFER_BIT);
735                 glColor4f(config.r ? 1 : 0, 
736                         config.g ? 1 : 0, 
737                         config.b ? 1 : 0, 
738                         config.a ? 1 : 0);
740                 get_output()->draw_texture(0,
741                         0,
742                         get_output()->get_w(),
743                         get_output()->get_h(),
744                         layer_table[i].x1,
745                         get_output()->get_h() - layer_table[i].y1,
746                         layer_table[i].x2,
747                         get_output()->get_h() - layer_table[i].y2,
748                         1);
750 // Fill YUV black
751                 glDisable(GL_TEXTURE_2D);
752                 if(cmodel_is_yuv(get_output()->get_color_model()))
753                 {
754                         glColor4f(config.r ? 0.0 : 0, 
755                                 config.g ? 0.5 : 0, 
756                                 config.b ? 0.5 : 0, 
757                                 config.a ? 1.0 : 0);
758                         float center_x1 = 0.0;
759                         float center_x2 = get_output()->get_w();
760                         if(layer_table[i].x1 > 0)
761                         {
762                                 center_x1 = layer_table[i].x1;
763                                 draw_box(0, 0, layer_table[i].x1, -get_output()->get_h());
764                         }
765                         if(layer_table[i].x2 < get_output()->get_w())
766                         {
767                                 center_x2 = layer_table[i].x2;
768                                 draw_box(layer_table[i].x2, 0, get_output()->get_w(), -get_output()->get_h());
769                         }
770                         if(layer_table[i].y1 > 0)
771                         {
772                                 draw_box(center_x1, 
773                                         -get_output()->get_h(), 
774                                         center_x2, 
775                                         -get_output()->get_h() + layer_table[i].y1);
776                         }
777                         if(layer_table[i].y2 < get_output()->get_h())
778                         {
779                                 draw_box(center_x1, 
780                                         -get_output()->get_h() + layer_table[i].y2, 
781                                         center_x2, 
782                                         0);
783                         }
784                 }
787                 glAccum(GL_ACCUM, fraction);
788                 glEnable(GL_TEXTURE_2D);
789                 glColor4f(config.r ? 1 : 0, 
790                         config.g ? 1 : 0, 
791                         config.b ? 1 : 0, 
792                         config.a ? 1 : 0);
793         }
795         glDisable(GL_BLEND);
796         glReadBuffer(GL_BACK);
797         glDisable(GL_TEXTURE_2D);
798         glAccum(GL_RETURN, 1.0);
800         glColor4f(1, 1, 1, 1);
801         get_output()->set_opengl_state(VFrame::SCREEN);
802 #endif
818 ZoomBlurPackage::ZoomBlurPackage()
819  : LoadPackage()
826 ZoomBlurUnit::ZoomBlurUnit(ZoomBlurEngine *server, 
827         ZoomBlurMain *plugin)
828  : LoadClient(server)
830         this->plugin = plugin;
831         this->server = server;
835 #define BLEND_LAYER(COMPONENTS, TYPE, TEMP_TYPE, MAX, DO_YUV) \
836 { \
837         const int chroma_offset = (DO_YUV ? ((MAX + 1) / 2) : 0); \
838         for(int j = pkg->y1; j < pkg->y2; j++) \
839         { \
840                 TEMP_TYPE *out_row = (TEMP_TYPE*)plugin->accum + COMPONENTS * w * j; \
841                 int in_y = y_table[j]; \
843 /* Blend image */ \
844                 if(in_y >= 0 && in_y < h) \
845                 { \
846                         TYPE *in_row = (TYPE*)plugin->input->get_rows()[in_y]; \
847                         for(int k = 0; k < w; k++) \
848                         { \
849                                 int in_x = x_table[k]; \
850 /* Blend pixel */ \
851                                 if(in_x >= 0 && in_x < w) \
852                                 { \
853                                         int in_offset = in_x * COMPONENTS; \
854                                         *out_row++ += in_row[in_offset]; \
855                                         if(DO_YUV) \
856                                         { \
857                                                 *out_row++ += in_row[in_offset + 1]; \
858                                                 *out_row++ += in_row[in_offset + 2]; \
859                                         } \
860                                         else \
861                                         { \
862                                                 *out_row++ += (TEMP_TYPE)in_row[in_offset + 1]; \
863                                                 *out_row++ += (TEMP_TYPE)in_row[in_offset + 2]; \
864                                         } \
865                                         if(COMPONENTS == 4) \
866                                                 *out_row++ += in_row[in_offset + 3]; \
867                                 } \
868 /* Blend nothing */ \
869                                 else \
870                                 { \
871                                         out_row++; \
872                                         if(DO_YUV) \
873                                         { \
874                                                 *out_row++ += chroma_offset; \
875                                                 *out_row++ += chroma_offset; \
876                                         } \
877                                         else \
878                                         { \
879                                                 out_row += 2; \
880                                         } \
881                                         if(COMPONENTS == 4) out_row++; \
882                                 } \
883                         } \
884                 } \
885                 else \
886                 if(DO_YUV) \
887                 { \
888                         for(int k = 0; k < w; k++) \
889                         { \
890                                 out_row++; \
891                                 *out_row++ += chroma_offset; \
892                                 *out_row++ += chroma_offset; \
893                                 if(COMPONENTS == 4) out_row++; \
894                         } \
895                 } \
896         } \
898 /* Copy just selected blurred channels to output and combine with original \
899         unblurred channels */ \
900         if(i == plugin->config.steps - 1) \
901         { \
902                 for(int j = pkg->y1; j < pkg->y2; j++) \
903                 { \
904                         TEMP_TYPE *in_row = (TEMP_TYPE*)plugin->accum + COMPONENTS * w * j; \
905                         TYPE *in_backup = (TYPE*)plugin->input->get_rows()[j]; \
906                         TYPE *out_row = (TYPE*)plugin->output->get_rows()[j]; \
907                         for(int k = 0; k < w; k++) \
908                         { \
909                                 if(do_r) \
910                                 { \
911                                         *out_row++ = (*in_row++ * fraction) / 0x10000; \
912                                         in_backup++; \
913                                 } \
914                                 else \
915                                 { \
916                                         *out_row++ = *in_backup++; \
917                                         in_row++; \
918                                 } \
920                                 if(DO_YUV) \
921                                 { \
922                                         if(do_g) \
923                                         { \
924                                                 *out_row++ = ((*in_row++ * fraction) / 0x10000); \
925                                                 in_backup++; \
926                                         } \
927                                         else \
928                                         { \
929                                                 *out_row++ = *in_backup++; \
930                                                 in_row++; \
931                                         } \
933                                         if(do_b) \
934                                         { \
935                                                 *out_row++ = ((*in_row++ * fraction) / 0x10000); \
936                                                 in_backup++; \
937                                         } \
938                                         else \
939                                         { \
940                                                 *out_row++ = *in_backup++; \
941                                                 in_row++; \
942                                         } \
943                                 } \
944                                 else \
945                                 { \
946                                         if(do_g) \
947                                         { \
948                                                 *out_row++ = (*in_row++ * fraction) / 0x10000; \
949                                                 in_backup++; \
950                                         } \
951                                         else \
952                                         { \
953                                                 *out_row++ = *in_backup++; \
954                                                 in_row++; \
955                                         } \
957                                         if(do_b) \
958                                         { \
959                                                 *out_row++ = (*in_row++ * fraction) / 0x10000; \
960                                                 in_backup++; \
961                                         } \
962                                         else \
963                                         { \
964                                                 *out_row++ = *in_backup++; \
965                                                 in_row++; \
966                                         } \
967                                 } \
969                                 if(COMPONENTS == 4) \
970                                 { \
971                                         if(do_a) \
972                                         { \
973                                                 *out_row++ = (*in_row++ * fraction) / 0x10000; \
974                                                 in_backup++; \
975                                         } \
976                                         else \
977                                         { \
978                                                 *out_row++ = *in_backup++; \
979                                                 in_row++; \
980                                         } \
981                                 } \
982                         } \
983                 } \
984         } \
987 void ZoomBlurUnit::process_package(LoadPackage *package)
989         ZoomBlurPackage *pkg = (ZoomBlurPackage*)package;
990         int h = plugin->output->get_h();
991         int w = plugin->output->get_w();
992         int do_r = plugin->config.r;
993         int do_g = plugin->config.g;
994         int do_b = plugin->config.b;
995         int do_a = plugin->config.a;
997         int fraction = 0x10000 / plugin->config.steps;
998         for(int i = 0; i < plugin->config.steps; i++)
999         {
1000                 int *x_table = plugin->scale_x_table[i];
1001                 int *y_table = plugin->scale_y_table[i];
1003                 switch(plugin->input->get_color_model())
1004                 {
1005                         case BC_RGB888:
1006                                 BLEND_LAYER(3, uint8_t, int, 0xff, 0)
1007                                 break;
1008                         case BC_RGB_FLOAT:
1009                                 BLEND_LAYER(3, float, float, 1, 0)
1010                                 break;
1011                         case BC_RGBA_FLOAT:
1012                                 BLEND_LAYER(4, float, float, 1, 0)
1013                                 break;
1014                         case BC_RGBA8888:
1015                                 BLEND_LAYER(4, uint8_t, int, 0xff, 0)
1016                                 break;
1017                         case BC_RGB161616:
1018                                 BLEND_LAYER(3, uint16_t, int, 0xffff, 0)
1019                                 break;
1020                         case BC_RGBA16161616:
1021                                 BLEND_LAYER(4, uint16_t, int, 0xffff, 0)
1022                                 break;
1023                         case BC_YUV888:
1024                                 BLEND_LAYER(3, uint8_t, int, 0xff, 1)
1025                                 break;
1026                         case BC_YUVA8888:
1027                                 BLEND_LAYER(4, uint8_t, int, 0xff, 1)
1028                                 break;
1029                         case BC_YUV161616:
1030                                 BLEND_LAYER(3, uint16_t, int, 0xffff, 1)
1031                                 break;
1032                         case BC_YUVA16161616:
1033                                 BLEND_LAYER(4, uint16_t, int, 0xffff, 1)
1034                                 break;
1035                 }
1036         }
1044 ZoomBlurEngine::ZoomBlurEngine(ZoomBlurMain *plugin, 
1045         int total_clients, 
1046         int total_packages)
1047  : LoadServer(total_clients, total_packages)
1049         this->plugin = plugin;
1052 void ZoomBlurEngine::init_packages()
1054         for(int i = 0; i < get_total_packages(); i++)
1055         {
1056                 ZoomBlurPackage *package = (ZoomBlurPackage*)get_package(i);
1057                 package->y1 = plugin->output->get_h() * i / get_total_packages();
1058                 package->y2 = plugin->output->get_h() * (i + 1) / get_total_packages();
1059         }
1062 LoadClient* ZoomBlurEngine::new_client()
1064         return new ZoomBlurUnit(this, plugin);
1067 LoadPackage* ZoomBlurEngine::new_package()
1069         return new ZoomBlurPackage;