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