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