PKGBUILD fix libva/vdpau deps
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / zoomblur / zoomblur.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 "zoomblur.h"
24
25
26
27 REGISTER_PLUGIN(ZoomBlurMain)
28
29
30
31 ZoomBlurConfig::ZoomBlurConfig()
32 {
33         reset(RESET_DEFAULT_SETTINGS);
34 }
35
36 void ZoomBlurConfig::reset(int clear)
37 {
38         switch(clear) {
39                 case RESET_ALL :
40                         x = 50;
41                         y = 50;
42                         radius = 0;
43                         steps = 1;
44                         r = 1;
45                         g = 1;
46                         b = 1;
47                         a = 1;
48                         break;
49                 case RESET_XSLIDER : x = 50;
50                         break;
51                 case RESET_YSLIDER : y = 50;
52                         break;
53                 case RESET_RADIUS : radius = 0;
54                         break;
55                 case RESET_STEPS : steps = 1;
56                         break;
57                 case RESET_DEFAULT_SETTINGS :
58                 default:
59                         x = 50;
60                         y = 50;
61                         radius = 10;
62                         steps = 10;
63                         r = 1;
64                         g = 1;
65                         b = 1;
66                         a = 1;
67                         break;
68         }
69 }
70
71 int ZoomBlurConfig::equivalent(ZoomBlurConfig &that)
72 {
73         return
74                 x == that.x &&
75                 y == that.y &&
76                 radius == that.radius &&
77                 steps == that.steps &&
78                 r == that.r &&
79                 g == that.g &&
80                 b == that.b &&
81                 a == that.a;
82 }
83
84 void ZoomBlurConfig::copy_from(ZoomBlurConfig &that)
85 {
86         x = that.x;
87         y = that.y;
88         radius = that.radius;
89         steps = that.steps;
90         r = that.r;
91         g = that.g;
92         b = that.b;
93         a = that.a;
94 }
95
96 void ZoomBlurConfig::interpolate(ZoomBlurConfig &prev,
97         ZoomBlurConfig &next,
98         long prev_frame,
99         long next_frame,
100         long current_frame)
101 {
102         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
103         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
104         this->x = (int)(prev.x * prev_scale + next.x * next_scale + 0.5);
105         this->y = (int)(prev.y * prev_scale + next.y * next_scale + 0.5);
106         this->radius = (int)(prev.radius * prev_scale + next.radius * next_scale + 0.5);
107         this->steps = (int)(prev.steps * prev_scale + next.steps * next_scale + 0.5);
108         r = prev.r;
109         g = prev.g;
110         b = prev.b;
111         a = prev.a;
112 }
113
114
115
116
117
118
119
120
121
122
123
124
125 ZoomBlurWindow::ZoomBlurWindow(ZoomBlurMain *plugin)
126  : PluginClientWindow(plugin,
127         280,
128         370,
129         280,
130         370,
131         0)
132 {
133         this->plugin = plugin;
134 }
135
136 ZoomBlurWindow::~ZoomBlurWindow()
137 {
138 }
139
140 void ZoomBlurWindow::create_objects()
141 {
142         int x = 10, y = 10;
143         int x1 = 0; int clrBtn_w = 50;
144         int defaultBtn_w = 100;
145
146         add_subwindow(new BC_Title(x, y, _("X:")));
147         y += 20;
148         add_subwindow(this->x = new ZoomBlurSize(plugin, x, y, &plugin->config.x, 0, 100));
149         x1 = x + this->x->get_w() + 10;
150         add_subwindow(xClr = new ZoomBlurSliderClr(plugin, this, x1, y, clrBtn_w, RESET_XSLIDER));
151
152         y += 30;
153         add_subwindow(new BC_Title(x, y, _("Y:")));
154         y += 20;
155         add_subwindow(this->y = new ZoomBlurSize(plugin, x, y, &plugin->config.y, 0, 100));
156         add_subwindow(yClr = new ZoomBlurSliderClr(plugin, this, x1, y, clrBtn_w, RESET_YSLIDER));
157
158         y += 30;
159         add_subwindow(new BC_Title(x, y, _("Radius:")));
160         y += 20;
161         add_subwindow(radius = new ZoomBlurSize(plugin, x, y, &plugin->config.radius, -100, 100));
162         add_subwindow(radiusClr = new ZoomBlurSliderClr(plugin, this, x1, y, clrBtn_w, RESET_RADIUS));
163
164         y += 30;
165         add_subwindow(new BC_Title(x, y, _("Steps:")));
166         y += 20;
167         add_subwindow(steps = new ZoomBlurSize(plugin, x, y, &plugin->config.steps, 1, 100));
168         add_subwindow(stepsClr = new ZoomBlurSliderClr(plugin, this, x1, y, clrBtn_w, RESET_STEPS));
169
170         y += 30;
171         add_subwindow(r = new ZoomBlurToggle(plugin, x, y, &plugin->config.r, _("Red")));
172         y += 30;
173         add_subwindow(g = new ZoomBlurToggle(plugin, x, y, &plugin->config.g, _("Green")));
174         y += 30;
175         add_subwindow(b = new ZoomBlurToggle(plugin, x, y, &plugin->config.b, _("Blue")));
176         y += 30;
177         add_subwindow(a = new ZoomBlurToggle(plugin, x, y, &plugin->config.a, _("Alpha")));
178         y += 40;
179         add_subwindow(reset = new ZoomBlurReset(plugin, this, x, y));
180         add_subwindow(default_settings = new ZoomBlurDefaultSettings(plugin, this,
181                 (280 - 10 - defaultBtn_w), y, defaultBtn_w));
182
183         show_window();
184         flush();
185 }
186
187 // for Reset button
188 void ZoomBlurWindow::update_gui(int clear)
189 {
190         switch(clear) {
191                 case RESET_XSLIDER : this->x->update(plugin->config.x);
192                         break;
193                 case RESET_YSLIDER : this->y->update(plugin->config.y);
194                         break;
195                 case RESET_RADIUS : radius->update(plugin->config.radius);
196                         break;
197                 case RESET_STEPS : steps->update(plugin->config.steps);
198                         break;
199                 case RESET_ALL :
200                 case RESET_DEFAULT_SETTINGS :
201                 default:
202                         this->x->update(plugin->config.x);
203                         this->y->update(plugin->config.x);
204                         radius->update(plugin->config.radius);
205                         steps->update(plugin->config.steps);
206                         r->update(plugin->config.r);
207                         g->update(plugin->config.g);
208                         b->update(plugin->config.b);
209                         a->update(plugin->config.a);
210                         break;
211         }
212 }
213
214
215
216
217
218
219
220
221
222
223 ZoomBlurToggle::ZoomBlurToggle(ZoomBlurMain *plugin,
224         int x,
225         int y,
226         int *output,
227         char *string)
228  : BC_CheckBox(x, y, *output, string)
229 {
230         this->plugin = plugin;
231         this->output = output;
232 }
233
234 int ZoomBlurToggle::handle_event()
235 {
236         *output = get_value();
237         plugin->send_configure_change();
238         return 1;
239 }
240
241
242
243
244
245
246
247 ZoomBlurSize::ZoomBlurSize(ZoomBlurMain *plugin,
248         int x,
249         int y,
250         int *output,
251         int min,
252         int max)
253  : BC_ISlider(x, y, 0, 200, 200, min, max, *output)
254 {
255         this->plugin = plugin;
256         this->output = output;
257 }
258 int ZoomBlurSize::handle_event()
259 {
260         *output = get_value();
261         plugin->send_configure_change();
262         return 1;
263 }
264
265
266 ZoomBlurReset::ZoomBlurReset(ZoomBlurMain *plugin, ZoomBlurWindow *window, int x, int y)
267  : BC_GenericButton(x, y, _("Reset"))
268 {
269         this->plugin = plugin;
270         this->window = window;
271 }
272 ZoomBlurReset::~ZoomBlurReset()
273 {
274 }
275 int ZoomBlurReset::handle_event()
276 {
277         plugin->config.reset(RESET_ALL);
278         window->update_gui(RESET_ALL);
279         plugin->send_configure_change();
280         return 1;
281 }
282
283
284 ZoomBlurDefaultSettings::ZoomBlurDefaultSettings(ZoomBlurMain *plugin, ZoomBlurWindow *window, int x, int y, int w)
285  : BC_GenericButton(x, y, w, _("Default"))
286 {
287         this->plugin = plugin;
288         this->window = window;
289 }
290 ZoomBlurDefaultSettings::~ZoomBlurDefaultSettings()
291 {
292 }
293 int ZoomBlurDefaultSettings::handle_event()
294 {
295         plugin->config.reset(RESET_DEFAULT_SETTINGS);
296         window->update_gui(RESET_DEFAULT_SETTINGS);
297         plugin->send_configure_change();
298         return 1;
299 }
300
301
302 ZoomBlurSliderClr::ZoomBlurSliderClr(ZoomBlurMain *plugin, ZoomBlurWindow *window, int x, int y, int w, int clear)
303  : BC_GenericButton(x, y, w, _("⌂"))
304 {
305         this->plugin = plugin;
306         this->window = window;
307         this->clear = clear;
308 }
309 ZoomBlurSliderClr::~ZoomBlurSliderClr()
310 {
311 }
312 int ZoomBlurSliderClr::handle_event()
313 {
314         // clear==1 ==> X slider
315         // clear==2 ==> Y slider
316         // clear==3 ==> Radius slider
317         // clear==4 ==> Steps slider
318         plugin->config.reset(clear);
319         window->update_gui(clear);
320         plugin->send_configure_change();
321         return 1;
322 }
323
324
325
326
327 ZoomBlurMain::ZoomBlurMain(PluginServer *server)
328  : PluginVClient(server)
329 {
330
331         engine = 0;
332         scale_x_table = 0;
333         scale_y_table = 0;
334         layer_table = 0;
335         table_entries = 0;
336         accum = 0;
337         need_reconfigure = 1;
338         temp = 0;
339 }
340
341 ZoomBlurMain::~ZoomBlurMain()
342 {
343
344         if(engine) delete engine;
345         delete_tables();
346         if(accum) delete [] accum;
347         if(temp) delete temp;
348 }
349
350 const char* ZoomBlurMain::plugin_title() { return N_("Zoom Blur"); }
351 int ZoomBlurMain::is_realtime() { return 1; }
352
353
354
355 NEW_WINDOW_MACRO(ZoomBlurMain, ZoomBlurWindow)
356
357 LOAD_CONFIGURATION_MACRO(ZoomBlurMain, ZoomBlurConfig)
358
359 void ZoomBlurMain::delete_tables()
360 {
361         if(scale_x_table)
362         {
363                 for(int i = 0; i < table_entries; i++)
364                         delete [] scale_x_table[i];
365                 delete [] scale_x_table;
366         }
367
368         if(scale_y_table)
369         {
370                 for(int i = 0; i < table_entries; i++)
371                         delete [] scale_y_table[i];
372                 delete [] scale_y_table;
373         }
374
375         delete [] layer_table;
376         scale_x_table = 0;
377         scale_y_table = 0;
378         layer_table = 0;
379         table_entries = 0;
380 }
381
382 int ZoomBlurMain::process_buffer(VFrame *frame,
383                 int64_t start_position,
384                 double frame_rate)
385 {
386         need_reconfigure |= load_configuration();
387
388
389 SET_TRACE
390         read_frame(frame,
391                 0,
392                 get_source_position(),
393                 get_framerate(),
394                 get_use_opengl());
395
396 SET_TRACE
397
398 // Generate tables here.  The same table is used by many packages to render
399 // each horizontal stripe.  Need to cover the entire output range in  each
400 // table to avoid green borders
401         if(need_reconfigure)
402         {
403 SET_TRACE
404                 float w = frame->get_w();
405                 float h = frame->get_h();
406                 float center_x = (float)config.x / 100 * w;
407                 float center_y = (float)config.y / 100 * h;
408                 float radius = (float)(100 + config.radius) / 100;
409                 float min_w, min_h;
410                 //float max_w, max_h;
411                 int steps = config.steps ? config.steps : 1;
412                 float min_x1;
413                 float min_y1;
414                 float min_x2;
415                 float min_y2;
416                 float max_x1;
417                 float max_y1;
418                 float max_x2;
419                 float max_y2;
420
421 SET_TRACE
422
423 // printf("ZoomBlurMain::process_realtime 1 %d %d\n",
424 // config.x,
425 // config.y);
426
427                 center_x = (center_x - w / 2) * (1.0 - radius) + w / 2;
428                 center_y = (center_y - h / 2) * (1.0 - radius) + h / 2;
429                 min_w = w * radius;
430                 min_h = h * radius;
431                 //max_w = w;
432                 //max_h = h;
433                 min_x1 = center_x - min_w / 2;
434                 min_y1 = center_y - min_h / 2;
435                 min_x2 = center_x + min_w / 2;
436                 min_y2 = center_y + min_h / 2;
437                 max_x1 = 0;
438                 max_y1 = 0;
439                 max_x2 = w;
440                 max_y2 = h;
441
442 SET_TRACE
443 // printf("ZoomBlurMain::process_realtime 2 w=%f radius=%f center_x=%f\n",
444 // w,
445 // radius,
446 // center_x);
447
448
449 // Dimensions of outermost rectangle
450
451                 delete_tables();
452                 table_entries = steps;
453                 scale_x_table = new int*[steps];
454                 scale_y_table = new int*[steps];
455                 layer_table = new ZoomBlurLayer[table_entries];
456
457 SET_TRACE
458                 for(int i = 0; i < steps; i++)
459                 {
460                         float fraction = (float)i / steps;
461                         float inv_fraction = 1.0 - fraction;
462                         float out_x1 = min_x1 * fraction + max_x1 * inv_fraction;
463                         float out_x2 = min_x2 * fraction + max_x2 * inv_fraction;
464                         float out_y1 = min_y1 * fraction + max_y1 * inv_fraction;
465                         float out_y2 = min_y2 * fraction + max_y2 * inv_fraction;
466                         float out_w = out_x2 - out_x1;
467                         float out_h = out_y2 - out_y1;
468                         if(out_w < 0) out_w = 0;
469                         if(out_h < 0) out_h = 0;
470                         float scale_x = (float)w / out_w;
471                         float scale_y = (float)h / out_h;
472
473                         int *x_table;
474                         int *y_table;
475                         scale_y_table[i] = y_table = new int[(int)(h + 1)];
476                         scale_x_table[i] = x_table = new int[(int)(w + 1)];
477 SET_TRACE
478                         layer_table[i].x1 = out_x1;
479                         layer_table[i].y1 = out_y1;
480                         layer_table[i].x2 = out_x2;
481                         layer_table[i].y2 = out_y2;
482 SET_TRACE
483
484                         for(int j = 0; j < h; j++)
485                         {
486                                 y_table[j] = (int)((j - out_y1) * scale_y);
487                         }
488                         for(int j = 0; j < w; j++)
489                         {
490                                 x_table[j] = (int)((j - out_x1) * scale_x);
491 //printf("ZoomBlurMain::process_realtime %d %d\n", j, x_table[j]);
492                         }
493                 }
494 SET_TRACE
495                 need_reconfigure = 0;
496         }
497
498 SET_TRACE
499         if(get_use_opengl()) return run_opengl();
500
501 SET_TRACE
502
503
504
505         if(!engine) engine = new ZoomBlurEngine(this,
506                 get_project_smp() + 1,
507                 get_project_smp() + 1);
508         if(!accum) accum = new unsigned char[frame->get_w() *
509                 frame->get_h() *
510                 BC_CModels::components(frame->get_color_model()) *
511                 MAX(sizeof(int), sizeof(float))];
512
513         this->input = frame;
514         this->output = frame;
515
516
517         if(!temp) temp = new VFrame(frame->get_w(), frame->get_h(),
518                 frame->get_color_model(), 0);
519         temp->copy_from(frame);
520         this->input = temp;
521
522         bzero(accum,
523                 frame->get_w() *
524                 frame->get_h() *
525                 BC_CModels::components(frame->get_color_model()) *
526                 MAX(sizeof(int), sizeof(float)));
527         engine->process_packages();
528         return 0;
529 }
530
531
532 void ZoomBlurMain::update_gui()
533 {
534         if(thread)
535         {
536                 load_configuration();
537                 thread->window->lock_window();
538                 ((ZoomBlurWindow*)thread->window)->x->update(config.x);
539                 ((ZoomBlurWindow*)thread->window)->y->update(config.y);
540                 ((ZoomBlurWindow*)thread->window)->radius->update(config.radius);
541                 ((ZoomBlurWindow*)thread->window)->steps->update(config.steps);
542                 ((ZoomBlurWindow*)thread->window)->r->update(config.r);
543                 ((ZoomBlurWindow*)thread->window)->g->update(config.g);
544                 ((ZoomBlurWindow*)thread->window)->b->update(config.b);
545                 ((ZoomBlurWindow*)thread->window)->a->update(config.a);
546                 thread->window->unlock_window();
547         }
548 }
549
550
551
552
553
554 void ZoomBlurMain::save_data(KeyFrame *keyframe)
555 {
556         FileXML output;
557
558 // cause data to be stored directly in text
559         output.set_shared_output(keyframe->xbuf);
560         output.tag.set_title("ZOOMBLUR");
561
562         output.tag.set_property("X", config.x);
563         output.tag.set_property("Y", config.y);
564         output.tag.set_property("RADIUS", config.radius);
565         output.tag.set_property("STEPS", config.steps);
566         output.tag.set_property("R", config.r);
567         output.tag.set_property("G", config.g);
568         output.tag.set_property("B", config.b);
569         output.tag.set_property("A", config.a);
570         output.append_tag();
571         output.tag.set_title("/ZOOMBLUR");
572         output.append_tag();
573         output.append_newline();
574         output.terminate_string();
575 }
576
577 void ZoomBlurMain::read_data(KeyFrame *keyframe)
578 {
579         FileXML input;
580
581         input.set_shared_input(keyframe->xbuf);
582
583         int result = 0;
584
585         while(!result)
586         {
587                 result = input.read_tag();
588
589                 if(!result)
590                 {
591                         if(input.tag.title_is("ZOOMBLUR"))
592                         {
593                                 config.x = input.tag.get_property("X", config.x);
594                                 config.y = input.tag.get_property("Y", config.y);
595                                 config.radius = input.tag.get_property("RADIUS", config.radius);
596                                 config.steps = input.tag.get_property("STEPS", config.steps);
597                                 config.r = input.tag.get_property("R", config.r);
598                                 config.g = input.tag.get_property("G", config.g);
599                                 config.b = input.tag.get_property("B", config.b);
600                                 config.a = input.tag.get_property("A", config.a);
601                         }
602                 }
603         }
604 }
605
606 #ifdef HAVE_GL
607 static void draw_box(float x1, float y1, float x2, float y2)
608 {
609         glBegin(GL_QUADS);
610         glVertex3f(x1, y1, 0.0);
611         glVertex3f(x2, y1, 0.0);
612         glVertex3f(x2, y2, 0.0);
613         glVertex3f(x1, y2, 0.0);
614         glEnd();
615 }
616 #endif
617
618 int ZoomBlurMain::handle_opengl()
619 {
620 #ifdef HAVE_GL
621         get_output()->to_texture();
622         get_output()->enable_opengl();
623         get_output()->init_screen();
624         get_output()->bind_texture(0);
625
626         //int is_yuv = BC_CModels::is_yuv(get_output()->get_color_model());
627         glClearColor(0.0, 0.0, 0.0, 0.0);
628         glClear(GL_COLOR_BUFFER_BIT);
629
630 // Draw unselected channels
631         glEnable(GL_BLEND);
632         glBlendFunc(GL_ONE, GL_ONE);
633         glDrawBuffer(GL_BACK);
634
635         if(!config.r || !config.g || !config.b || !config.a)
636         {
637                 glColor4f(config.r ? 0 : 1,
638                         config.g ? 0 : 1,
639                         config.b ? 0 : 1,
640                         config.a ? 0 : 1);
641                 get_output()->draw_texture();
642         }
643         glAccum(GL_LOAD, 1.0);
644
645 // Blur selected channels
646         float fraction = 1.0 / config.steps;
647         for(int i = 0; i < config.steps; i++)
648         {
649                 glClear(GL_COLOR_BUFFER_BIT);
650                 glColor4f(config.r ? 1 : 0,
651                         config.g ? 1 : 0,
652                         config.b ? 1 : 0,
653                         config.a ? 1 : 0);
654
655                 get_output()->draw_texture(0,
656                         0,
657                         get_output()->get_w(),
658                         get_output()->get_h(),
659                         layer_table[i].x1,
660                         get_output()->get_h() - layer_table[i].y1,
661                         layer_table[i].x2,
662                         get_output()->get_h() - layer_table[i].y2,
663                         1);
664
665 // Fill YUV black
666                 glDisable(GL_TEXTURE_2D);
667                 if(BC_CModels::is_yuv(get_output()->get_color_model()))
668                 {
669                         glColor4f(config.r ? 0.0 : 0,
670                                 config.g ? 0.5 : 0,
671                                 config.b ? 0.5 : 0,
672                                 config.a ? 1.0 : 0);
673                         float center_x1 = 0.0;
674                         float center_x2 = get_output()->get_w();
675                         if(layer_table[i].x1 > 0)
676                         {
677                                 center_x1 = layer_table[i].x1;
678                                 draw_box(0, 0, layer_table[i].x1, -get_output()->get_h());
679                         }
680                         if(layer_table[i].x2 < get_output()->get_w())
681                         {
682                                 center_x2 = layer_table[i].x2;
683                                 draw_box(layer_table[i].x2, 0, get_output()->get_w(), -get_output()->get_h());
684                         }
685                         if(layer_table[i].y1 > 0)
686                         {
687                                 draw_box(center_x1,
688                                         -get_output()->get_h(),
689                                         center_x2,
690                                         -get_output()->get_h() + layer_table[i].y1);
691                         }
692                         if(layer_table[i].y2 < get_output()->get_h())
693                         {
694                                 draw_box(center_x1,
695                                         -get_output()->get_h() + layer_table[i].y2,
696                                         center_x2,
697                                         0);
698                         }
699                 }
700
701
702                 glAccum(GL_ACCUM, fraction);
703                 glEnable(GL_TEXTURE_2D);
704                 glColor4f(config.r ? 1 : 0,
705                         config.g ? 1 : 0,
706                         config.b ? 1 : 0,
707                         config.a ? 1 : 0);
708         }
709
710         glDisable(GL_BLEND);
711         glReadBuffer(GL_BACK);
712         glDisable(GL_TEXTURE_2D);
713         glAccum(GL_RETURN, 1.0);
714
715         glColor4f(1, 1, 1, 1);
716         get_output()->set_opengl_state(VFrame::SCREEN);
717 #endif
718         return 0;
719 }
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734 ZoomBlurPackage::ZoomBlurPackage()
735  : LoadPackage()
736 {
737 }
738
739
740
741
742 ZoomBlurUnit::ZoomBlurUnit(ZoomBlurEngine *server,
743         ZoomBlurMain *plugin)
744  : LoadClient(server)
745 {
746         this->plugin = plugin;
747         this->server = server;
748 }
749
750
751 #define BLEND_LAYER(COMPONENTS, TYPE, TEMP_TYPE, MAX, DO_YUV) \
752 { \
753         const int chroma_offset = (DO_YUV ? ((MAX + 1) / 2) : 0); \
754         for(int j = pkg->y1; j < pkg->y2; j++) \
755         { \
756                 TEMP_TYPE *out_row = (TEMP_TYPE*)plugin->accum + COMPONENTS * w * j; \
757                 int in_y = y_table[j]; \
758  \
759 /* Blend image */ \
760                 if(in_y >= 0 && in_y < h) \
761                 { \
762                         TYPE *in_row = (TYPE*)plugin->input->get_rows()[in_y]; \
763                         for(int k = 0; k < w; k++) \
764                         { \
765                                 int in_x = x_table[k]; \
766 /* Blend pixel */ \
767                                 if(in_x >= 0 && in_x < w) \
768                                 { \
769                                         int in_offset = in_x * COMPONENTS; \
770                                         *out_row++ += in_row[in_offset]; \
771                                         if(DO_YUV) \
772                                         { \
773                                                 *out_row++ += in_row[in_offset + 1]; \
774                                                 *out_row++ += in_row[in_offset + 2]; \
775                                         } \
776                                         else \
777                                         { \
778                                                 *out_row++ += (TEMP_TYPE)in_row[in_offset + 1]; \
779                                                 *out_row++ += (TEMP_TYPE)in_row[in_offset + 2]; \
780                                         } \
781                                         if(COMPONENTS == 4) \
782                                                 *out_row++ += in_row[in_offset + 3]; \
783                                 } \
784 /* Blend nothing */ \
785                                 else \
786                                 { \
787                                         out_row++; \
788                                         if(DO_YUV) \
789                                         { \
790                                                 *out_row++ += chroma_offset; \
791                                                 *out_row++ += chroma_offset; \
792                                         } \
793                                         else \
794                                         { \
795                                                 out_row += 2; \
796                                         } \
797                                         if(COMPONENTS == 4) out_row++; \
798                                 } \
799                         } \
800                 } \
801                 else \
802                 if(DO_YUV) \
803                 { \
804                         for(int k = 0; k < w; k++) \
805                         { \
806                                 out_row++; \
807                                 *out_row++ += chroma_offset; \
808                                 *out_row++ += chroma_offset; \
809                                 if(COMPONENTS == 4) out_row++; \
810                         } \
811                 } \
812         } \
813  \
814 /* Copy just selected blurred channels to output and combine with original \
815         unblurred channels */ \
816         if(i == plugin->config.steps - 1) \
817         { \
818                 for(int j = pkg->y1; j < pkg->y2; j++) \
819                 { \
820                         TEMP_TYPE *in_row = (TEMP_TYPE*)plugin->accum + COMPONENTS * w * j; \
821                         TYPE *in_backup = (TYPE*)plugin->input->get_rows()[j]; \
822                         TYPE *out_row = (TYPE*)plugin->output->get_rows()[j]; \
823                         for(int k = 0; k < w; k++) \
824                         { \
825                                 if(do_r) \
826                                 { \
827                                         *out_row++ = (*in_row++ * fraction) / 0x10000; \
828                                         in_backup++; \
829                                 } \
830                                 else \
831                                 { \
832                                         *out_row++ = *in_backup++; \
833                                         in_row++; \
834                                 } \
835  \
836                                 if(DO_YUV) \
837                                 { \
838                                         if(do_g) \
839                                         { \
840                                                 *out_row++ = ((*in_row++ * fraction) / 0x10000); \
841                                                 in_backup++; \
842                                         } \
843                                         else \
844                                         { \
845                                                 *out_row++ = *in_backup++; \
846                                                 in_row++; \
847                                         } \
848  \
849                                         if(do_b) \
850                                         { \
851                                                 *out_row++ = ((*in_row++ * fraction) / 0x10000); \
852                                                 in_backup++; \
853                                         } \
854                                         else \
855                                         { \
856                                                 *out_row++ = *in_backup++; \
857                                                 in_row++; \
858                                         } \
859                                 } \
860                                 else \
861                                 { \
862                                         if(do_g) \
863                                         { \
864                                                 *out_row++ = (*in_row++ * fraction) / 0x10000; \
865                                                 in_backup++; \
866                                         } \
867                                         else \
868                                         { \
869                                                 *out_row++ = *in_backup++; \
870                                                 in_row++; \
871                                         } \
872  \
873                                         if(do_b) \
874                                         { \
875                                                 *out_row++ = (*in_row++ * fraction) / 0x10000; \
876                                                 in_backup++; \
877                                         } \
878                                         else \
879                                         { \
880                                                 *out_row++ = *in_backup++; \
881                                                 in_row++; \
882                                         } \
883                                 } \
884  \
885                                 if(COMPONENTS == 4) \
886                                 { \
887                                         if(do_a) \
888                                         { \
889                                                 *out_row++ = (*in_row++ * fraction) / 0x10000; \
890                                                 in_backup++; \
891                                         } \
892                                         else \
893                                         { \
894                                                 *out_row++ = *in_backup++; \
895                                                 in_row++; \
896                                         } \
897                                 } \
898                         } \
899                 } \
900         } \
901 }
902
903 void ZoomBlurUnit::process_package(LoadPackage *package)
904 {
905         ZoomBlurPackage *pkg = (ZoomBlurPackage*)package;
906         int h = plugin->output->get_h();
907         int w = plugin->output->get_w();
908         int do_r = plugin->config.r;
909         int do_g = plugin->config.g;
910         int do_b = plugin->config.b;
911         int do_a = plugin->config.a;
912
913         int fraction = 0x10000 / plugin->config.steps;
914         for(int i = 0; i < plugin->config.steps; i++)
915         {
916                 int *x_table = plugin->scale_x_table[i];
917                 int *y_table = plugin->scale_y_table[i];
918
919                 switch(plugin->input->get_color_model())
920                 {
921                         case BC_RGB888:
922                                 BLEND_LAYER(3, uint8_t, int, 0xff, 0)
923                                 break;
924                         case BC_RGB_FLOAT:
925                                 BLEND_LAYER(3, float, float, 1, 0)
926                                 break;
927                         case BC_RGBA_FLOAT:
928                                 BLEND_LAYER(4, float, float, 1, 0)
929                                 break;
930                         case BC_RGBA8888:
931                                 BLEND_LAYER(4, uint8_t, int, 0xff, 0)
932                                 break;
933                         case BC_RGB161616:
934                                 BLEND_LAYER(3, uint16_t, int, 0xffff, 0)
935                                 break;
936                         case BC_RGBA16161616:
937                                 BLEND_LAYER(4, uint16_t, int, 0xffff, 0)
938                                 break;
939                         case BC_YUV888:
940                                 BLEND_LAYER(3, uint8_t, int, 0xff, 1)
941                                 break;
942                         case BC_YUVA8888:
943                                 BLEND_LAYER(4, uint8_t, int, 0xff, 1)
944                                 break;
945                         case BC_YUV161616:
946                                 BLEND_LAYER(3, uint16_t, int, 0xffff, 1)
947                                 break;
948                         case BC_YUVA16161616:
949                                 BLEND_LAYER(4, uint16_t, int, 0xffff, 1)
950                                 break;
951                 }
952         }
953 }
954
955
956
957
958
959
960 ZoomBlurEngine::ZoomBlurEngine(ZoomBlurMain *plugin,
961         int total_clients,
962         int total_packages)
963  : LoadServer(total_clients, total_packages)
964 {
965         this->plugin = plugin;
966 }
967
968 void ZoomBlurEngine::init_packages()
969 {
970         for(int i = 0; i < get_total_packages(); i++)
971         {
972                 ZoomBlurPackage *package = (ZoomBlurPackage*)get_package(i);
973                 package->y1 = plugin->output->get_h() * i / get_total_packages();
974                 package->y2 = plugin->output->get_h() * (i + 1) / get_total_packages();
975         }
976 }
977
978 LoadClient* ZoomBlurEngine::new_client()
979 {
980         return new ZoomBlurUnit(this, plugin);
981 }
982
983 LoadPackage* ZoomBlurEngine::new_package()
984 {
985         return new ZoomBlurPackage;
986 }
987
988
989
990
991