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