dynamic keyframes, textbox rework, andrea ffmpeg.opts, perpetual chkpt undo, lv2...
[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 N_("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)
522                 temp = new VFrame(frame->get_w(), frame->get_h(),
523                         frame->get_color_model(), 0);
524         temp->copy_from(frame);
525         this->input = temp;
526
527
528         bzero(accum,
529                 frame->get_w() *
530                 frame->get_h() *
531                 BC_CModels::components(frame->get_color_model()) *
532                 MAX(sizeof(int), sizeof(float)));
533         engine->process_packages();
534         return 0;
535 }
536
537
538 void LinearBlurMain::update_gui()
539 {
540         if(thread)
541         {
542                 load_configuration();
543                 ((LinearBlurWindow*)thread->window)->lock_window();
544                 ((LinearBlurWindow*)thread->window)->radius->update(config.radius);
545                 ((LinearBlurWindow*)thread->window)->angle->update(config.angle);
546                 ((LinearBlurWindow*)thread->window)->steps->update(config.steps);
547                 ((LinearBlurWindow*)thread->window)->r->update(config.r);
548                 ((LinearBlurWindow*)thread->window)->g->update(config.g);
549                 ((LinearBlurWindow*)thread->window)->b->update(config.b);
550                 ((LinearBlurWindow*)thread->window)->a->update(config.a);
551                 ((LinearBlurWindow*)thread->window)->unlock_window();
552         }
553 }
554
555
556
557 void LinearBlurMain::save_data(KeyFrame *keyframe)
558 {
559         FileXML output;
560
561 // cause data to be stored directly in text
562         output.set_shared_output(keyframe->xbuf);
563         output.tag.set_title("LINEARBLUR");
564
565         output.tag.set_property("RADIUS", config.radius);
566         output.tag.set_property("ANGLE", config.angle);
567         output.tag.set_property("STEPS", config.steps);
568         output.tag.set_property("R", config.r);
569         output.tag.set_property("G", config.g);
570         output.tag.set_property("B", config.b);
571         output.tag.set_property("A", config.a);
572         output.append_tag();
573         output.tag.set_title("/LINEARBLUR");
574         output.append_tag();
575         output.append_newline();
576         output.terminate_string();
577 }
578
579 void LinearBlurMain::read_data(KeyFrame *keyframe)
580 {
581         FileXML input;
582
583         input.set_shared_input(keyframe->xbuf);
584
585         int result = 0;
586
587         while(!result)
588         {
589                 result = input.read_tag();
590
591                 if(!result)
592                 {
593                         if(input.tag.title_is("LINEARBLUR"))
594                         {
595                                 config.radius = input.tag.get_property("RADIUS", config.radius);
596                                 config.angle = input.tag.get_property("ANGLE", config.angle);
597                                 config.steps = input.tag.get_property("STEPS", config.steps);
598                                 config.r = input.tag.get_property("R", config.r);
599                                 config.g = input.tag.get_property("G", config.g);
600                                 config.b = input.tag.get_property("B", config.b);
601                                 config.a = input.tag.get_property("A", config.a);
602                         }
603                 }
604         }
605 }
606
607 #ifdef HAVE_GL
608 static void draw_box(float x1, float y1, float x2, float y2)
609 {
610         glBegin(GL_QUADS);
611         glVertex3f(x1, y1, 0.0);
612         glVertex3f(x2, y1, 0.0);
613         glVertex3f(x2, y2, 0.0);
614         glVertex3f(x1, y2, 0.0);
615         glEnd();
616 }
617 #endif
618
619 int LinearBlurMain::handle_opengl()
620 {
621 #ifdef HAVE_GL
622         get_output()->to_texture();
623         get_output()->enable_opengl();
624         get_output()->init_screen();
625         get_output()->bind_texture(0);
626
627         int is_yuv = BC_CModels::is_yuv(get_output()->get_color_model());
628         glClearColor(0.0, 0.0, 0.0, 0.0);
629         glClear(GL_COLOR_BUFFER_BIT);
630
631 // Draw unselected channels
632         glEnable(GL_BLEND);
633         glBlendFunc(GL_ONE, GL_ONE);
634         glDrawBuffer(GL_BACK);
635         if(!config.r || !config.g || !config.b || !config.a)
636         {
637                 glColor4f(config.r ? 0 : 1,
638                         config.g ? 0 : 1,
639                         config.b ? 0 : 1,
640                         config.a ? 0 : 1);
641                 get_output()->draw_texture();
642         }
643         glAccum(GL_LOAD, 1.0);
644
645 // Blur selected channels
646         float fraction = 1.0 / config.steps;
647         for(int i = 0; i < config.steps; i++)
648         {
649                 glClear(GL_COLOR_BUFFER_BIT);
650                 glColor4f(config.r ? 1 : 0,
651                         config.g ? 1 : 0,
652                         config.b ? 1 : 0,
653                         config.a ? 1 : 0);
654
655                 int w = get_output()->get_w();
656                 int h = get_output()->get_h();
657                 get_output()->draw_texture(0,
658                         0,
659                         w,
660                         h,
661                         layer_table[i].x,
662                         get_output()->get_h() - layer_table[i].y,
663                         layer_table[i].x + w,
664                         get_output()->get_h() - layer_table[i].y - h,
665                         1);
666
667
668 // Fill YUV black
669                 glDisable(GL_TEXTURE_2D);
670                 if(is_yuv)
671                 {
672                         glColor4f(config.r ? 0.0 : 0,
673                                 config.g ? 0.5 : 0,
674                                 config.b ? 0.5 : 0,
675                                 config.a ? 1.0 : 0);
676                         float center_x1 = 0.0;
677                         float center_x2 = get_output()->get_w();
678                         float project_x1 = layer_table[i].x;
679                         float project_x2 = layer_table[i].x + get_output()->get_w();
680                         float project_y1 = layer_table[i].y;
681                         float project_y2 = layer_table[i].y + get_output()->get_h();
682                         if(project_x1 > 0)
683                         {
684                                 center_x1 = project_x1;
685                                 draw_box(0, 0, project_x1, -get_output()->get_h());
686                         }
687                         if(project_x2 < get_output()->get_w())
688                         {
689                                 center_x2 = project_x2;
690                                 draw_box(project_x2, 0, get_output()->get_w(), -get_output()->get_h());
691                         }
692                         if(project_y1 > 0)
693                         {
694                                 draw_box(center_x1,
695                                         -get_output()->get_h(),
696                                         center_x2,
697                                         -get_output()->get_h() + project_y1);
698                         }
699                         if(project_y2 < get_output()->get_h())
700                         {
701                                 draw_box(center_x1,
702                                         -get_output()->get_h() + project_y2,
703                                         center_x2,
704                                         0);
705                         }
706                 }
707
708
709
710
711                 glAccum(GL_ACCUM, fraction);
712                 glEnable(GL_TEXTURE_2D);
713                 glColor4f(config.r ? 1 : 0,
714                         config.g ? 1 : 0,
715                         config.b ? 1 : 0,
716                         config.a ? 1 : 0);
717         }
718
719         glDisable(GL_BLEND);
720         glDisable(GL_TEXTURE_2D);
721         glReadBuffer(GL_BACK);
722         glAccum(GL_RETURN, 1.0);
723
724         glColor4f(1, 1, 1, 1);
725         get_output()->set_opengl_state(VFrame::SCREEN);
726 #endif
727         return 0;
728 }
729
730
731
732
733
734
735 LinearBlurPackage::LinearBlurPackage()
736  : LoadPackage()
737 {
738 }
739
740
741
742
743 LinearBlurUnit::LinearBlurUnit(LinearBlurEngine *server,
744         LinearBlurMain *plugin)
745  : LoadClient(server)
746 {
747         this->plugin = plugin;
748         this->server = server;
749 }
750
751
752 #define BLEND_LAYER(COMPONENTS, TYPE, TEMP, MAX, DO_YUV) \
753 { \
754         for(int j = pkg->y1; j < pkg->y2; j++) \
755         { \
756                 TEMP *out_row = (TEMP*)plugin->accum + COMPONENTS * w * j; \
757                 int in_y = y_table[j]; \
758  \
759 /* Blend image */ \
760                 TYPE *in_row = (TYPE*)plugin->input->get_rows()[in_y]; \
761                 for(int k = 0; k < w; k++) \
762                 { \
763                         int in_x = x_table[k]; \
764 /* Blend pixel */ \
765                         int in_offset = in_x * COMPONENTS; \
766                         *out_row++ += in_row[in_offset]; \
767                         if(DO_YUV) \
768                         { \
769                                 *out_row++ += in_row[in_offset + 1]; \
770                                 *out_row++ += in_row[in_offset + 2]; \
771                         } \
772                         else \
773                         { \
774                                 *out_row++ += in_row[in_offset + 1]; \
775                                 *out_row++ += in_row[in_offset + 2]; \
776                         } \
777                         if(COMPONENTS == 4) \
778                                 *out_row++ += in_row[in_offset + 3]; \
779                 } \
780         } \
781  \
782 /* Copy to output */ \
783         if(i == plugin->config.steps - 1) \
784         { \
785                 for(int j = pkg->y1; j < pkg->y2; j++) \
786                 { \
787                         TEMP *in_row = (TEMP*)plugin->accum + COMPONENTS * w * j; \
788                         TYPE *in_backup = (TYPE*)plugin->input->get_rows()[j]; \
789                         TYPE *out_row = (TYPE*)plugin->output->get_rows()[j]; \
790                         for(int k = 0; k < w; k++) \
791                         { \
792                                 if(do_r) \
793                                 { \
794                                         *out_row++ = (*in_row++ * fraction) / 0x10000; \
795                                         in_backup++; \
796                                 } \
797                                 else \
798                                 { \
799                                         *out_row++ = *in_backup++; \
800                                         in_row++; \
801                                 } \
802  \
803                                 if(DO_YUV) \
804                                 { \
805                                         if(do_g) \
806                                         { \
807                                                 *out_row++ = (*in_row++ * fraction) / 0x10000; \
808                                                 in_backup++; \
809                                         } \
810                                         else \
811                                         { \
812                                                 *out_row++ = *in_backup++; \
813                                                 in_row++; \
814                                         } \
815  \
816                                         if(do_b) \
817                                         { \
818                                                 *out_row++ = (*in_row++ * fraction) / 0x10000; \
819                                                 in_backup++; \
820                                         } \
821                                         else \
822                                         { \
823                                                 *out_row++ = *in_backup++; \
824                                                 in_row++; \
825                                         } \
826                                 } \
827                                 else \
828                                 { \
829                                         if(do_g) \
830                                         { \
831                                                 *out_row++ = (*in_row++ * fraction) / 0x10000; \
832                                                 in_backup++; \
833                                         } \
834                                         else \
835                                         { \
836                                                 *out_row++ = *in_backup++; \
837                                                 in_row++; \
838                                         } \
839  \
840                                         if(do_b) \
841                                         { \
842                                                 *out_row++ = (*in_row++ * fraction) / 0x10000; \
843                                                 in_backup++; \
844                                         } \
845                                         else \
846                                         { \
847                                                 *out_row++ = *in_backup++; \
848                                                 in_row++; \
849                                         } \
850                                 } \
851  \
852                                 if(COMPONENTS == 4) \
853                                 { \
854                                         if(do_a) \
855                                         { \
856                                                 *out_row++ = (*in_row++ * fraction) / 0x10000; \
857                                                 in_backup++; \
858                                         } \
859                                         else \
860                                         { \
861                                                 *out_row++ = *in_backup++; \
862                                                 in_row++; \
863                                         } \
864                                 } \
865                         } \
866                 } \
867         } \
868 }
869
870 void LinearBlurUnit::process_package(LoadPackage *package)
871 {
872         LinearBlurPackage *pkg = (LinearBlurPackage*)package;
873         //int h = plugin->output->get_h();
874         int w = plugin->output->get_w();
875
876         int fraction = 0x10000 / plugin->config.steps;
877         int do_r = plugin->config.r;
878         int do_g = plugin->config.g;
879         int do_b = plugin->config.b;
880         int do_a = plugin->config.a;
881         for(int i = 0; i < plugin->config.steps; i++)
882         {
883                 int *x_table = plugin->scale_x_table[i];
884                 int *y_table = plugin->scale_y_table[i];
885
886                 switch(plugin->input->get_color_model())
887                 {
888                         case BC_RGB_FLOAT:
889                                 BLEND_LAYER(3, float, float, 1, 0)
890                                 break;
891                         case BC_RGB888:
892                                 BLEND_LAYER(3, uint8_t, int, 0xff, 0)
893                                 break;
894                         case BC_RGBA_FLOAT:
895                                 BLEND_LAYER(4, float, float, 1, 0)
896                                 break;
897                         case BC_RGBA8888:
898                                 BLEND_LAYER(4, uint8_t, int, 0xff, 0)
899                                 break;
900                         case BC_RGB161616:
901                                 BLEND_LAYER(3, uint16_t, int, 0xffff, 0)
902                                 break;
903                         case BC_RGBA16161616:
904                                 BLEND_LAYER(4, uint16_t, int, 0xffff, 0)
905                                 break;
906                         case BC_YUV888:
907                                 BLEND_LAYER(3, uint8_t, int, 0xff, 1)
908                                 break;
909                         case BC_YUVA8888:
910                                 BLEND_LAYER(4, uint8_t, int, 0xff, 1)
911                                 break;
912                         case BC_YUV161616:
913                                 BLEND_LAYER(3, uint16_t, int, 0xffff, 1)
914                                 break;
915                         case BC_YUVA16161616:
916                                 BLEND_LAYER(4, uint16_t, int, 0xffff, 1)
917                                 break;
918                 }
919         }
920 }
921
922
923
924
925
926
927 LinearBlurEngine::LinearBlurEngine(LinearBlurMain *plugin,
928         int total_clients,
929         int total_packages)
930  : LoadServer(total_clients, total_packages)
931 {
932         this->plugin = plugin;
933 }
934
935 void LinearBlurEngine::init_packages()
936 {
937         for(int i = 0; i < get_total_packages(); i++)
938         {
939                 LinearBlurPackage *package = (LinearBlurPackage*)get_package(i);
940                 package->y1 = plugin->output->get_h() * i / get_total_packages();
941                 package->y2 = plugin->output->get_h() * (i + 1) / get_total_packages();
942         }
943 }
944
945 LoadClient* LinearBlurEngine::new_client()
946 {
947         return new LinearBlurUnit(this, plugin);
948 }
949
950 LoadPackage* LinearBlurEngine::new_package()
951 {
952         return new LinearBlurPackage;
953 }
954
955
956
957
958