aa7e87b1c210dc3f9d611fd077d8a5194146f98e
[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(frame->get_w(), frame->get_h(),
570                 frame->get_color_model(), 0);
571         temp->copy_from(frame);
572         this->input = temp;
573
574         bzero(accum,
575                 frame->get_w() *
576                 frame->get_h() *
577                 BC_CModels::components(frame->get_color_model()) *
578                 MAX(sizeof(int), sizeof(float)));
579         engine->process_packages();
580         return 0;
581 }
582
583
584 void ZoomBlurMain::update_gui()
585 {
586         if(thread)
587         {
588                 load_configuration();
589                 thread->window->lock_window();
590                 ((ZoomBlurWindow*)thread->window)->x->update(config.x);
591                 ((ZoomBlurWindow*)thread->window)->y->update(config.y);
592                 ((ZoomBlurWindow*)thread->window)->radius->update(config.radius);
593                 ((ZoomBlurWindow*)thread->window)->steps->update(config.steps);
594                 ((ZoomBlurWindow*)thread->window)->r->update(config.r);
595                 ((ZoomBlurWindow*)thread->window)->g->update(config.g);
596                 ((ZoomBlurWindow*)thread->window)->b->update(config.b);
597                 ((ZoomBlurWindow*)thread->window)->a->update(config.a);
598                 thread->window->unlock_window();
599         }
600 }
601
602
603
604
605
606 void ZoomBlurMain::save_data(KeyFrame *keyframe)
607 {
608         FileXML output;
609
610 // cause data to be stored directly in text
611         output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
612         output.tag.set_title("ZOOMBLUR");
613
614         output.tag.set_property("X", config.x);
615         output.tag.set_property("Y", config.y);
616         output.tag.set_property("RADIUS", config.radius);
617         output.tag.set_property("STEPS", config.steps);
618         output.tag.set_property("R", config.r);
619         output.tag.set_property("G", config.g);
620         output.tag.set_property("B", config.b);
621         output.tag.set_property("A", config.a);
622         output.append_tag();
623         output.tag.set_title("/ZOOMBLUR");
624         output.append_tag();
625         output.append_newline();
626         output.terminate_string();
627 }
628
629 void ZoomBlurMain::read_data(KeyFrame *keyframe)
630 {
631         FileXML input;
632
633         input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
634
635         int result = 0;
636
637         while(!result)
638         {
639                 result = input.read_tag();
640
641                 if(!result)
642                 {
643                         if(input.tag.title_is("ZOOMBLUR"))
644                         {
645                                 config.x = input.tag.get_property("X", config.x);
646                                 config.y = input.tag.get_property("Y", config.y);
647                                 config.radius = input.tag.get_property("RADIUS", config.radius);
648                                 config.steps = input.tag.get_property("STEPS", config.steps);
649                                 config.r = input.tag.get_property("R", config.r);
650                                 config.g = input.tag.get_property("G", config.g);
651                                 config.b = input.tag.get_property("B", config.b);
652                                 config.a = input.tag.get_property("A", config.a);
653                         }
654                 }
655         }
656 }
657
658 #ifdef HAVE_GL
659 static void draw_box(float x1, float y1, float x2, float y2)
660 {
661         glBegin(GL_QUADS);
662         glVertex3f(x1, y1, 0.0);
663         glVertex3f(x2, y1, 0.0);
664         glVertex3f(x2, y2, 0.0);
665         glVertex3f(x1, y2, 0.0);
666         glEnd();
667 }
668 #endif
669
670 int ZoomBlurMain::handle_opengl()
671 {
672 #ifdef HAVE_GL
673         get_output()->to_texture();
674         get_output()->enable_opengl();
675         get_output()->init_screen();
676         get_output()->bind_texture(0);
677
678         //int is_yuv = BC_CModels::is_yuv(get_output()->get_color_model());
679         glClearColor(0.0, 0.0, 0.0, 0.0);
680         glClear(GL_COLOR_BUFFER_BIT);
681
682 // Draw unselected channels
683         glEnable(GL_BLEND);
684         glBlendFunc(GL_ONE, GL_ONE);
685         glDrawBuffer(GL_BACK);
686
687         if(!config.r || !config.g || !config.b || !config.a)
688         {
689                 glColor4f(config.r ? 0 : 1,
690                         config.g ? 0 : 1,
691                         config.b ? 0 : 1,
692                         config.a ? 0 : 1);
693                 get_output()->draw_texture();
694         }
695         glAccum(GL_LOAD, 1.0);
696
697 // Blur selected channels
698         float fraction = 1.0 / config.steps;
699         for(int i = 0; i < config.steps; i++)
700         {
701                 glClear(GL_COLOR_BUFFER_BIT);
702                 glColor4f(config.r ? 1 : 0,
703                         config.g ? 1 : 0,
704                         config.b ? 1 : 0,
705                         config.a ? 1 : 0);
706
707                 get_output()->draw_texture(0,
708                         0,
709                         get_output()->get_w(),
710                         get_output()->get_h(),
711                         layer_table[i].x1,
712                         get_output()->get_h() - layer_table[i].y1,
713                         layer_table[i].x2,
714                         get_output()->get_h() - layer_table[i].y2,
715                         1);
716
717 // Fill YUV black
718                 glDisable(GL_TEXTURE_2D);
719                 if(BC_CModels::is_yuv(get_output()->get_color_model()))
720                 {
721                         glColor4f(config.r ? 0.0 : 0,
722                                 config.g ? 0.5 : 0,
723                                 config.b ? 0.5 : 0,
724                                 config.a ? 1.0 : 0);
725                         float center_x1 = 0.0;
726                         float center_x2 = get_output()->get_w();
727                         if(layer_table[i].x1 > 0)
728                         {
729                                 center_x1 = layer_table[i].x1;
730                                 draw_box(0, 0, layer_table[i].x1, -get_output()->get_h());
731                         }
732                         if(layer_table[i].x2 < get_output()->get_w())
733                         {
734                                 center_x2 = layer_table[i].x2;
735                                 draw_box(layer_table[i].x2, 0, get_output()->get_w(), -get_output()->get_h());
736                         }
737                         if(layer_table[i].y1 > 0)
738                         {
739                                 draw_box(center_x1,
740                                         -get_output()->get_h(),
741                                         center_x2,
742                                         -get_output()->get_h() + layer_table[i].y1);
743                         }
744                         if(layer_table[i].y2 < get_output()->get_h())
745                         {
746                                 draw_box(center_x1,
747                                         -get_output()->get_h() + layer_table[i].y2,
748                                         center_x2,
749                                         0);
750                         }
751                 }
752
753
754                 glAccum(GL_ACCUM, fraction);
755                 glEnable(GL_TEXTURE_2D);
756                 glColor4f(config.r ? 1 : 0,
757                         config.g ? 1 : 0,
758                         config.b ? 1 : 0,
759                         config.a ? 1 : 0);
760         }
761
762         glDisable(GL_BLEND);
763         glReadBuffer(GL_BACK);
764         glDisable(GL_TEXTURE_2D);
765         glAccum(GL_RETURN, 1.0);
766
767         glColor4f(1, 1, 1, 1);
768         get_output()->set_opengl_state(VFrame::SCREEN);
769 #endif
770         return 0;
771 }
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786 ZoomBlurPackage::ZoomBlurPackage()
787  : LoadPackage()
788 {
789 }
790
791
792
793
794 ZoomBlurUnit::ZoomBlurUnit(ZoomBlurEngine *server,
795         ZoomBlurMain *plugin)
796  : LoadClient(server)
797 {
798         this->plugin = plugin;
799         this->server = server;
800 }
801
802
803 #define BLEND_LAYER(COMPONENTS, TYPE, TEMP_TYPE, MAX, DO_YUV) \
804 { \
805         const int chroma_offset = (DO_YUV ? ((MAX + 1) / 2) : 0); \
806         for(int j = pkg->y1; j < pkg->y2; j++) \
807         { \
808                 TEMP_TYPE *out_row = (TEMP_TYPE*)plugin->accum + COMPONENTS * w * j; \
809                 int in_y = y_table[j]; \
810  \
811 /* Blend image */ \
812                 if(in_y >= 0 && in_y < h) \
813                 { \
814                         TYPE *in_row = (TYPE*)plugin->input->get_rows()[in_y]; \
815                         for(int k = 0; k < w; k++) \
816                         { \
817                                 int in_x = x_table[k]; \
818 /* Blend pixel */ \
819                                 if(in_x >= 0 && in_x < w) \
820                                 { \
821                                         int in_offset = in_x * COMPONENTS; \
822                                         *out_row++ += in_row[in_offset]; \
823                                         if(DO_YUV) \
824                                         { \
825                                                 *out_row++ += in_row[in_offset + 1]; \
826                                                 *out_row++ += in_row[in_offset + 2]; \
827                                         } \
828                                         else \
829                                         { \
830                                                 *out_row++ += (TEMP_TYPE)in_row[in_offset + 1]; \
831                                                 *out_row++ += (TEMP_TYPE)in_row[in_offset + 2]; \
832                                         } \
833                                         if(COMPONENTS == 4) \
834                                                 *out_row++ += in_row[in_offset + 3]; \
835                                 } \
836 /* Blend nothing */ \
837                                 else \
838                                 { \
839                                         out_row++; \
840                                         if(DO_YUV) \
841                                         { \
842                                                 *out_row++ += chroma_offset; \
843                                                 *out_row++ += chroma_offset; \
844                                         } \
845                                         else \
846                                         { \
847                                                 out_row += 2; \
848                                         } \
849                                         if(COMPONENTS == 4) out_row++; \
850                                 } \
851                         } \
852                 } \
853                 else \
854                 if(DO_YUV) \
855                 { \
856                         for(int k = 0; k < w; k++) \
857                         { \
858                                 out_row++; \
859                                 *out_row++ += chroma_offset; \
860                                 *out_row++ += chroma_offset; \
861                                 if(COMPONENTS == 4) out_row++; \
862                         } \
863                 } \
864         } \
865  \
866 /* Copy just selected blurred channels to output and combine with original \
867         unblurred channels */ \
868         if(i == plugin->config.steps - 1) \
869         { \
870                 for(int j = pkg->y1; j < pkg->y2; j++) \
871                 { \
872                         TEMP_TYPE *in_row = (TEMP_TYPE*)plugin->accum + COMPONENTS * w * j; \
873                         TYPE *in_backup = (TYPE*)plugin->input->get_rows()[j]; \
874                         TYPE *out_row = (TYPE*)plugin->output->get_rows()[j]; \
875                         for(int k = 0; k < w; k++) \
876                         { \
877                                 if(do_r) \
878                                 { \
879                                         *out_row++ = (*in_row++ * fraction) / 0x10000; \
880                                         in_backup++; \
881                                 } \
882                                 else \
883                                 { \
884                                         *out_row++ = *in_backup++; \
885                                         in_row++; \
886                                 } \
887  \
888                                 if(DO_YUV) \
889                                 { \
890                                         if(do_g) \
891                                         { \
892                                                 *out_row++ = ((*in_row++ * fraction) / 0x10000); \
893                                                 in_backup++; \
894                                         } \
895                                         else \
896                                         { \
897                                                 *out_row++ = *in_backup++; \
898                                                 in_row++; \
899                                         } \
900  \
901                                         if(do_b) \
902                                         { \
903                                                 *out_row++ = ((*in_row++ * fraction) / 0x10000); \
904                                                 in_backup++; \
905                                         } \
906                                         else \
907                                         { \
908                                                 *out_row++ = *in_backup++; \
909                                                 in_row++; \
910                                         } \
911                                 } \
912                                 else \
913                                 { \
914                                         if(do_g) \
915                                         { \
916                                                 *out_row++ = (*in_row++ * fraction) / 0x10000; \
917                                                 in_backup++; \
918                                         } \
919                                         else \
920                                         { \
921                                                 *out_row++ = *in_backup++; \
922                                                 in_row++; \
923                                         } \
924  \
925                                         if(do_b) \
926                                         { \
927                                                 *out_row++ = (*in_row++ * fraction) / 0x10000; \
928                                                 in_backup++; \
929                                         } \
930                                         else \
931                                         { \
932                                                 *out_row++ = *in_backup++; \
933                                                 in_row++; \
934                                         } \
935                                 } \
936  \
937                                 if(COMPONENTS == 4) \
938                                 { \
939                                         if(do_a) \
940                                         { \
941                                                 *out_row++ = (*in_row++ * fraction) / 0x10000; \
942                                                 in_backup++; \
943                                         } \
944                                         else \
945                                         { \
946                                                 *out_row++ = *in_backup++; \
947                                                 in_row++; \
948                                         } \
949                                 } \
950                         } \
951                 } \
952         } \
953 }
954
955 void ZoomBlurUnit::process_package(LoadPackage *package)
956 {
957         ZoomBlurPackage *pkg = (ZoomBlurPackage*)package;
958         int h = plugin->output->get_h();
959         int w = plugin->output->get_w();
960         int do_r = plugin->config.r;
961         int do_g = plugin->config.g;
962         int do_b = plugin->config.b;
963         int do_a = plugin->config.a;
964
965         int fraction = 0x10000 / plugin->config.steps;
966         for(int i = 0; i < plugin->config.steps; i++)
967         {
968                 int *x_table = plugin->scale_x_table[i];
969                 int *y_table = plugin->scale_y_table[i];
970
971                 switch(plugin->input->get_color_model())
972                 {
973                         case BC_RGB888:
974                                 BLEND_LAYER(3, uint8_t, int, 0xff, 0)
975                                 break;
976                         case BC_RGB_FLOAT:
977                                 BLEND_LAYER(3, float, float, 1, 0)
978                                 break;
979                         case BC_RGBA_FLOAT:
980                                 BLEND_LAYER(4, float, float, 1, 0)
981                                 break;
982                         case BC_RGBA8888:
983                                 BLEND_LAYER(4, uint8_t, int, 0xff, 0)
984                                 break;
985                         case BC_RGB161616:
986                                 BLEND_LAYER(3, uint16_t, int, 0xffff, 0)
987                                 break;
988                         case BC_RGBA16161616:
989                                 BLEND_LAYER(4, uint16_t, int, 0xffff, 0)
990                                 break;
991                         case BC_YUV888:
992                                 BLEND_LAYER(3, uint8_t, int, 0xff, 1)
993                                 break;
994                         case BC_YUVA8888:
995                                 BLEND_LAYER(4, uint8_t, int, 0xff, 1)
996                                 break;
997                         case BC_YUV161616:
998                                 BLEND_LAYER(3, uint16_t, int, 0xffff, 1)
999                                 break;
1000                         case BC_YUVA16161616:
1001                                 BLEND_LAYER(4, uint16_t, int, 0xffff, 1)
1002                                 break;
1003                 }
1004         }
1005 }
1006
1007
1008
1009
1010
1011
1012 ZoomBlurEngine::ZoomBlurEngine(ZoomBlurMain *plugin,
1013         int total_clients,
1014         int total_packages)
1015  : LoadServer(total_clients, total_packages)
1016 {
1017         this->plugin = plugin;
1018 }
1019
1020 void ZoomBlurEngine::init_packages()
1021 {
1022         for(int i = 0; i < get_total_packages(); i++)
1023         {
1024                 ZoomBlurPackage *package = (ZoomBlurPackage*)get_package(i);
1025                 package->y1 = plugin->output->get_h() * i / get_total_packages();
1026                 package->y2 = plugin->output->get_h() * (i + 1) / get_total_packages();
1027         }
1028 }
1029
1030 LoadClient* ZoomBlurEngine::new_client()
1031 {
1032         return new ZoomBlurUnit(this, plugin);
1033 }
1034
1035 LoadPackage* ZoomBlurEngine::new_package()
1036 {
1037         return new ZoomBlurPackage;
1038 }
1039
1040
1041
1042
1043