no longer need ffmpeg patch0 which was for Termux
[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(420),
139         yS(200),
140         xS(420),
141         yS(200),
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), xs100 = xS(100), xs200 = xS(200);
154         int ys10 = yS(10), ys30 = yS(30), ys40 = yS(40);
155         int x = xs10, y = ys10;
156         int x2 = xS(80), x3 = xS(180);
157         int clr_x = get_w()-x - xS(22); // note: clrBtn_w = 22
158         int defaultBtn_w = xs100;
159
160         BC_Bar *bar;
161
162         y += ys10;
163         add_subwindow(new BC_Title(x, y, _("Length:")));
164         radius_text = new LinearBlurIText(this, plugin,
165                 0, &plugin->config.radius, (x + x2), y, RADIUS_MIN, RADIUS_MAX);
166         radius_text->create_objects();
167         radius_slider = new LinearBlurISlider(plugin,
168                 radius_text, &plugin->config.radius, x3, y, RADIUS_MIN, RADIUS_MAX, xs200);
169         add_subwindow(radius_slider);
170         radius_text->slider = radius_slider;
171         clr_x = x3 + radius_slider->get_w() + x;
172         add_subwindow(radius_Clr = new LinearBlurClr(plugin, this, clr_x, y, RESET_RADIUS));
173         y += ys30;
174
175         add_subwindow(new BC_Title(x, y, _("Angle:")));
176         angle_text = new LinearBlurIText(this, plugin,
177                 0, &plugin->config.angle, (x + x2), y, -ANGLE_MAX, ANGLE_MAX);
178         angle_text->create_objects();
179         angle_slider = new LinearBlurISlider(plugin,
180                 angle_text, &plugin->config.angle, x3, y, -ANGLE_MAX, ANGLE_MAX, xs200);
181         add_subwindow(angle_slider);
182         angle_text->slider = angle_slider;
183         add_subwindow(angle_Clr = new LinearBlurClr(plugin, this, clr_x, y, RESET_ANGLE));
184         y += ys30;
185
186         add_subwindow(new BC_Title(x, y, _("Steps:")));
187         steps_text = new LinearBlurIText(this, plugin,
188                 0, &plugin->config.steps, (x + x2), y, STEPS_MIN, STEPS_MAX);
189         steps_text->create_objects();
190         steps_slider = new LinearBlurISlider(plugin,
191                 steps_text, &plugin->config.steps, x3, y, STEPS_MIN, STEPS_MAX, xs200);
192         add_subwindow(steps_slider);
193         steps_text->slider = steps_slider;
194         add_subwindow(steps_Clr = new LinearBlurClr(plugin, this, clr_x, y, RESET_STEPS));
195         y += ys40;
196
197         add_subwindow(bar = new BC_Bar(x, y, get_w()-2*x));
198         y += ys10;
199         int x1 = x;
200         int toggle_w = (get_w()-2*x) / 4;
201         add_subwindow(r = new LinearBlurToggle(plugin, x1, y, &plugin->config.r, _("Red")));
202         x1 += toggle_w;
203         add_subwindow(g = new LinearBlurToggle(plugin, x1, y, &plugin->config.g, _("Green")));
204         x1 += toggle_w;
205         add_subwindow(b = new LinearBlurToggle(plugin, x1, y, &plugin->config.b, _("Blue")));
206         x1 += toggle_w;
207         add_subwindow(a = new LinearBlurToggle(plugin, x1, y, &plugin->config.a, _("Alpha")));
208         y += ys30;
209
210 // Reset section
211         add_subwindow(bar = new BC_Bar(x, y, get_w()-2*x));
212         y += ys10;
213         add_subwindow(reset = new LinearBlurReset(plugin, this, x, y));
214         add_subwindow(default_settings = new LinearBlurDefaultSettings(plugin, this,
215                 (get_w() - xs10 - defaultBtn_w), y, defaultBtn_w));
216
217         show_window();
218         flush();
219 }
220
221
222 // for Reset button
223 void LinearBlurWindow::update_gui(int clear)
224 {
225         switch(clear) {
226                 case RESET_RADIUS :
227                         radius_text->update((int64_t)plugin->config.radius);
228                         radius_slider->update(plugin->config.radius);
229                         break;
230                 case RESET_ANGLE :
231                         angle_text->update((int64_t)plugin->config.angle);
232                         angle_slider->update(plugin->config.angle);
233                         break;
234                 case RESET_STEPS :
235                         steps_text->update((int64_t)plugin->config.steps);
236                         steps_slider->update(plugin->config.steps);
237                         break;
238                 case RESET_ALL :
239                 case RESET_DEFAULT_SETTINGS :
240                 default:
241                         radius_text->update((int64_t)plugin->config.radius);
242                         radius_slider->update(plugin->config.radius);
243                         angle_text->update((int64_t)plugin->config.angle);
244                         angle_slider->update(plugin->config.angle);
245                         steps_text->update((int64_t)plugin->config.steps);
246                         steps_slider->update(plugin->config.steps);
247                         r->update(plugin->config.r);
248                         g->update(plugin->config.g);
249                         b->update(plugin->config.b);
250                         a->update(plugin->config.a);
251                         break;
252         }
253 }
254
255
256
257
258
259
260
261
262
263
264 LinearBlurToggle::LinearBlurToggle(LinearBlurMain *plugin,
265         int x,
266         int y,
267         int *output,
268         char *string)
269  : BC_CheckBox(x, y, *output, string)
270 {
271         this->plugin = plugin;
272         this->output = output;
273 }
274
275 int LinearBlurToggle::handle_event()
276 {
277         *output = get_value();
278         plugin->send_configure_change();
279         return 1;
280 }
281
282
283
284
285 LinearBlurIText::LinearBlurIText(LinearBlurWindow *gui, LinearBlurMain *plugin,
286         LinearBlurISlider *slider, int *output, int x, int y, int min, int max)
287  : BC_TumbleTextBox(gui, *output,
288         min, max, x, y, xS(60), 0)
289 {
290         this->gui = gui;
291         this->plugin = plugin;
292         this->output = output;
293         this->slider = slider;
294         this->min = min;
295         this->max = max;
296         set_increment(1);
297 }
298
299 LinearBlurIText::~LinearBlurIText()
300 {
301 }
302
303 int LinearBlurIText::handle_event()
304 {
305         *output = atoi(get_text());
306         if(*output > max) *output = max;
307         if(*output < min) *output = min;
308         slider->update(*output);
309         plugin->send_configure_change();
310         return 1;
311 }
312
313
314 LinearBlurISlider::LinearBlurISlider(LinearBlurMain *plugin,
315         LinearBlurIText *text, int *output, int x, int y, int min, int max, int w)
316  : BC_ISlider(x, y, 0, w, w, min, max, *output)
317 {
318         this->plugin = plugin;
319         this->output = output;
320         this->text = text;
321         enable_show_value(0); // Hide caption
322 }
323
324 LinearBlurISlider::~LinearBlurISlider()
325 {
326 }
327
328 int LinearBlurISlider::handle_event()
329 {
330         *output = get_value();
331         text->update((int64_t)*output);
332         plugin->send_configure_change();
333         return 1;
334 }
335
336
337 LinearBlurSize::LinearBlurSize(LinearBlurMain *plugin,
338         int x,
339         int y,
340         int *output,
341         int min,
342         int max)
343  : BC_ISlider(x, y, 0, xS(200), yS(200), min, max, *output)
344 {
345         this->plugin = plugin;
346         this->output = output;
347 }
348 int LinearBlurSize::handle_event()
349 {
350         *output = get_value();
351         plugin->send_configure_change();
352         return 1;
353 }
354
355
356 LinearBlurReset::LinearBlurReset(LinearBlurMain *plugin, LinearBlurWindow *gui, int x, int y)
357  : BC_GenericButton(x, y, _("Reset"))
358 {
359         this->plugin = plugin;
360         this->gui = gui;
361 }
362 LinearBlurReset::~LinearBlurReset()
363 {
364 }
365 int LinearBlurReset::handle_event()
366 {
367         plugin->config.reset(RESET_ALL);
368         gui->update_gui(RESET_ALL);
369         plugin->send_configure_change();
370         return 1;
371 }
372
373
374 LinearBlurDefaultSettings::LinearBlurDefaultSettings(LinearBlurMain *plugin, LinearBlurWindow *gui, int x, int y, int w)
375  : BC_GenericButton(x, y, w, _("Default"))
376 {
377         this->plugin = plugin;
378         this->gui = gui;
379 }
380 LinearBlurDefaultSettings::~LinearBlurDefaultSettings()
381 {
382 }
383 int LinearBlurDefaultSettings::handle_event()
384 {
385         plugin->config.reset(RESET_DEFAULT_SETTINGS);
386         gui->update_gui(RESET_DEFAULT_SETTINGS);
387         plugin->send_configure_change();
388         return 1;
389 }
390
391
392 LinearBlurClr::LinearBlurClr(LinearBlurMain *plugin, LinearBlurWindow *gui, int x, int y, int clear)
393  : BC_Button(x, y, plugin->get_theme()->get_image_set("reset_button"))
394 {
395         this->plugin = plugin;
396         this->gui = gui;
397         this->clear = clear;
398 }
399 LinearBlurClr::~LinearBlurClr()
400 {
401 }
402 int LinearBlurClr::handle_event()
403 {
404         // clear==1 ==> Radius slider
405         // clear==2 ==> Angle slider
406         // clear==3 ==> Steps slider
407         plugin->config.reset(clear);
408         gui->update_gui(clear);
409         plugin->send_configure_change();
410         return 1;
411 }
412
413
414
415
416
417
418
419
420 LinearBlurMain::LinearBlurMain(PluginServer *server)
421  : PluginVClient(server)
422 {
423
424         engine = 0;
425         scale_x_table = 0;
426         scale_y_table = 0;
427         table_entries = 0;
428         accum = 0;
429         need_reconfigure = 1;
430         temp = 0;
431         layer_table = 0;
432 }
433
434 LinearBlurMain::~LinearBlurMain()
435 {
436
437         if(engine) delete engine;
438         delete_tables();
439         if(accum) delete [] accum;
440         if(temp) delete temp;
441 }
442
443 const char* LinearBlurMain::plugin_title() { return N_("Linear Blur"); }
444 int LinearBlurMain::is_realtime() { return 1; }
445
446
447 NEW_WINDOW_MACRO(LinearBlurMain, LinearBlurWindow)
448 LOAD_CONFIGURATION_MACRO(LinearBlurMain, LinearBlurConfig)
449
450 void LinearBlurMain::delete_tables()
451 {
452         if(scale_x_table)
453         {
454                 for(int i = 0; i < table_entries; i++)
455                         delete [] scale_x_table[i];
456                 delete [] scale_x_table;
457         }
458
459         if(scale_y_table)
460         {
461                 for(int i = 0; i < table_entries; i++)
462                         delete [] scale_y_table[i];
463                 delete [] scale_y_table;
464         }
465         delete [] layer_table;
466         layer_table = 0;
467         scale_x_table = 0;
468         scale_y_table = 0;
469         table_entries = 0;
470 }
471
472 int LinearBlurMain::process_buffer(VFrame *frame,
473                                                         int64_t start_position,
474                                                         double frame_rate)
475 {
476         need_reconfigure |= load_configuration();
477
478         read_frame(frame,
479                 0,
480                 get_source_position(),
481                 get_framerate(),
482                 get_use_opengl());
483
484 // Generate tables here.  The same table is used by many packages to render
485 // each horizontal stripe.  Need to cover the entire output range in  each
486 // table to avoid green borders
487         if(need_reconfigure)
488         {
489                 int w = frame->get_w();
490                 int h = frame->get_h();
491                 int x_offset;
492                 int y_offset;
493                 int angle = config.angle;
494                 int radius = config.radius * MIN(w, h) / 100;
495
496                 while(angle < 0) angle += 360;
497                 switch(angle)
498                 {
499                         case 0:
500                         case 360:
501                                 x_offset = radius;
502                                 y_offset = 0;
503                                 break;
504                         case 90:
505                                 x_offset = 0;
506                                 y_offset = radius;
507                                 break;
508                         case 180:
509                                 x_offset = radius;
510                                 y_offset = 0;
511                                 break;
512                         case 270:
513                                 x_offset = 0;
514                                 y_offset = radius;
515                                 break;
516                         default:
517                                 y_offset = (int)(sin((float)config.angle / 360 * 2 * M_PI) * radius);
518                                 x_offset = (int)(cos((float)config.angle / 360 * 2 * M_PI) * radius);
519                                 break;
520                 }
521
522
523                 delete_tables();
524                 scale_x_table = new int*[config.steps];
525                 scale_y_table = new int*[config.steps];
526                 table_entries = config.steps;
527                 layer_table = new LinearBlurLayer[table_entries];
528
529 //printf("LinearBlurMain::process_realtime 1 %d %d %d\n", radius, x_offset, y_offset);
530
531                 for(int i = 0; i < config.steps; i++)
532                 {
533                         float fraction = (float)(i - config.steps / 2) / config.steps;
534                         int x = (int)(fraction * x_offset);
535                         int y = (int)(fraction * y_offset);
536
537                         int *x_table;
538                         int *y_table;
539                         scale_y_table[i] = y_table = new int[h];
540                         scale_x_table[i] = x_table = new int[w];
541
542                         layer_table[i].x = x;
543                         layer_table[i].y = y;
544                         for(int j = 0; j < h; j++)
545                         {
546                                 y_table[j] = j + y;
547                                 CLAMP(y_table[j], 0, h - 1);
548                         }
549                         for(int j = 0; j < w; j++)
550                         {
551                                 x_table[j] = j + x;
552                                 CLAMP(x_table[j], 0, w - 1);
553                         }
554                 }
555                 need_reconfigure = 0;
556         }
557
558         if(get_use_opengl()) return run_opengl();
559
560
561         if(!engine) engine = new LinearBlurEngine(this,
562                 get_project_smp() + 1,
563                 get_project_smp() + 1);
564         if(!accum) accum = new unsigned char[frame->get_w() *
565                 frame->get_h() *
566                 BC_CModels::components(frame->get_color_model()) *
567                 MAX(sizeof(int), sizeof(float))];
568
569         this->input = frame;
570         this->output = frame;
571
572
573         if(!temp)
574                 temp = new VFrame(frame->get_w(), frame->get_h(),
575                         frame->get_color_model(), 0);
576         temp->copy_from(frame);
577         this->input = temp;
578
579
580         bzero(accum,
581                 frame->get_w() *
582                 frame->get_h() *
583                 BC_CModels::components(frame->get_color_model()) *
584                 MAX(sizeof(int), sizeof(float)));
585         engine->process_packages();
586         return 0;
587 }
588
589
590 void LinearBlurMain::update_gui()
591 {
592         if(thread)
593         {
594                 load_configuration();
595                 ((LinearBlurWindow*)thread->window)->lock_window();
596                 ((LinearBlurWindow*)thread->window)->radius_text->update((int64_t)config.radius);
597                 ((LinearBlurWindow*)thread->window)->radius_slider->update(config.radius);
598                 ((LinearBlurWindow*)thread->window)->angle_text->update((int64_t)config.angle);
599                 ((LinearBlurWindow*)thread->window)->angle_slider->update(config.angle);
600                 ((LinearBlurWindow*)thread->window)->steps_text->update((int64_t)config.steps);
601                 ((LinearBlurWindow*)thread->window)->steps_slider->update(config.steps);
602
603                 ((LinearBlurWindow*)thread->window)->r->update(config.r);
604                 ((LinearBlurWindow*)thread->window)->g->update(config.g);
605                 ((LinearBlurWindow*)thread->window)->b->update(config.b);
606                 ((LinearBlurWindow*)thread->window)->a->update(config.a);
607                 ((LinearBlurWindow*)thread->window)->unlock_window();
608         }
609 }
610
611
612
613 void LinearBlurMain::save_data(KeyFrame *keyframe)
614 {
615         FileXML output;
616
617 // cause data to be stored directly in text
618         output.set_shared_output(keyframe->xbuf);
619         output.tag.set_title("LINEARBLUR");
620
621         output.tag.set_property("RADIUS", config.radius);
622         output.tag.set_property("ANGLE", config.angle);
623         output.tag.set_property("STEPS", config.steps);
624         output.tag.set_property("R", config.r);
625         output.tag.set_property("G", config.g);
626         output.tag.set_property("B", config.b);
627         output.tag.set_property("A", config.a);
628         output.append_tag();
629         output.tag.set_title("/LINEARBLUR");
630         output.append_tag();
631         output.append_newline();
632         output.terminate_string();
633 }
634
635 void LinearBlurMain::read_data(KeyFrame *keyframe)
636 {
637         FileXML input;
638
639         input.set_shared_input(keyframe->xbuf);
640
641         int result = 0;
642
643         while(!result)
644         {
645                 result = input.read_tag();
646
647                 if(!result)
648                 {
649                         if(input.tag.title_is("LINEARBLUR"))
650                         {
651                                 config.radius = input.tag.get_property("RADIUS", config.radius);
652                                 config.angle = input.tag.get_property("ANGLE", config.angle);
653                                 config.steps = input.tag.get_property("STEPS", config.steps);
654                                 config.r = input.tag.get_property("R", config.r);
655                                 config.g = input.tag.get_property("G", config.g);
656                                 config.b = input.tag.get_property("B", config.b);
657                                 config.a = input.tag.get_property("A", config.a);
658                         }
659                 }
660         }
661 }
662
663 #ifdef HAVE_GL
664 static void draw_box(float x1, float y1, float x2, float y2)
665 {
666         glBegin(GL_QUADS);
667         glVertex3f(x1, y1, 0.0);
668         glVertex3f(x2, y1, 0.0);
669         glVertex3f(x2, y2, 0.0);
670         glVertex3f(x1, y2, 0.0);
671         glEnd();
672 }
673 #endif
674
675 int LinearBlurMain::handle_opengl()
676 {
677 #ifdef HAVE_GL
678         get_output()->to_texture();
679         get_output()->enable_opengl();
680         get_output()->init_screen();
681         get_output()->bind_texture(0);
682
683         int is_yuv = BC_CModels::is_yuv(get_output()->get_color_model());
684         glClearColor(0.0, 0.0, 0.0, 0.0);
685         glClear(GL_COLOR_BUFFER_BIT);
686
687 // Draw unselected channels
688         glEnable(GL_BLEND);
689         glBlendFunc(GL_ONE, GL_ONE);
690         glDrawBuffer(GL_BACK);
691         if(!config.r || !config.g || !config.b || !config.a)
692         {
693                 glColor4f(config.r ? 0 : 1,
694                         config.g ? 0 : 1,
695                         config.b ? 0 : 1,
696                         config.a ? 0 : 1);
697                 get_output()->draw_texture();
698         }
699         glAccum(GL_LOAD, 1.0);
700
701 // Blur selected channels
702         float fraction = 1.0 / config.steps;
703         for(int i = 0; i < config.steps; i++)
704         {
705                 glClear(GL_COLOR_BUFFER_BIT);
706                 glColor4f(config.r ? 1 : 0,
707                         config.g ? 1 : 0,
708                         config.b ? 1 : 0,
709                         config.a ? 1 : 0);
710
711                 int w = get_output()->get_w();
712                 int h = get_output()->get_h();
713                 get_output()->draw_texture(0,
714                         0,
715                         w,
716                         h,
717                         layer_table[i].x,
718                         get_output()->get_h() - layer_table[i].y,
719                         layer_table[i].x + w,
720                         get_output()->get_h() - layer_table[i].y - h,
721                         1);
722
723
724 // Fill YUV black
725                 glDisable(GL_TEXTURE_2D);
726                 if(is_yuv)
727                 {
728                         glColor4f(config.r ? 0.0 : 0,
729                                 config.g ? 0.5 : 0,
730                                 config.b ? 0.5 : 0,
731                                 config.a ? 1.0 : 0);
732                         float center_x1 = 0.0;
733                         float center_x2 = get_output()->get_w();
734                         float project_x1 = layer_table[i].x;
735                         float project_x2 = layer_table[i].x + get_output()->get_w();
736                         float project_y1 = layer_table[i].y;
737                         float project_y2 = layer_table[i].y + get_output()->get_h();
738                         if(project_x1 > 0)
739                         {
740                                 center_x1 = project_x1;
741                                 draw_box(0, 0, project_x1, -get_output()->get_h());
742                         }
743                         if(project_x2 < get_output()->get_w())
744                         {
745                                 center_x2 = project_x2;
746                                 draw_box(project_x2, 0, get_output()->get_w(), -get_output()->get_h());
747                         }
748                         if(project_y1 > 0)
749                         {
750                                 draw_box(center_x1,
751                                         -get_output()->get_h(),
752                                         center_x2,
753                                         -get_output()->get_h() + project_y1);
754                         }
755                         if(project_y2 < get_output()->get_h())
756                         {
757                                 draw_box(center_x1,
758                                         -get_output()->get_h() + project_y2,
759                                         center_x2,
760                                         0);
761                         }
762                 }
763
764
765
766
767                 glAccum(GL_ACCUM, fraction);
768                 glEnable(GL_TEXTURE_2D);
769                 glColor4f(config.r ? 1 : 0,
770                         config.g ? 1 : 0,
771                         config.b ? 1 : 0,
772                         config.a ? 1 : 0);
773         }
774
775         glDisable(GL_BLEND);
776         glDisable(GL_TEXTURE_2D);
777         glReadBuffer(GL_BACK);
778         glAccum(GL_RETURN, 1.0);
779
780         glColor4f(1, 1, 1, 1);
781         get_output()->set_opengl_state(VFrame::SCREEN);
782 #endif
783         return 0;
784 }
785
786
787
788
789
790
791 LinearBlurPackage::LinearBlurPackage()
792  : LoadPackage()
793 {
794 }
795
796
797
798
799 LinearBlurUnit::LinearBlurUnit(LinearBlurEngine *server,
800         LinearBlurMain *plugin)
801  : LoadClient(server)
802 {
803         this->plugin = plugin;
804         this->server = server;
805 }
806
807
808 #define BLEND_LAYER(COMPONENTS, TYPE, TEMP, MAX, DO_YUV) \
809 { \
810         for(int j = pkg->y1; j < pkg->y2; j++) \
811         { \
812                 TEMP *out_row = (TEMP*)plugin->accum + COMPONENTS * w * j; \
813                 int in_y = y_table[j]; \
814  \
815 /* Blend image */ \
816                 TYPE *in_row = (TYPE*)plugin->input->get_rows()[in_y]; \
817                 for(int k = 0; k < w; k++) \
818                 { \
819                         int in_x = x_table[k]; \
820 /* Blend pixel */ \
821                         int in_offset = in_x * COMPONENTS; \
822                         *out_row++ += in_row[in_offset]; \
823                         if(DO_YUV) \
824                         { \
825                                 *out_row++ += in_row[in_offset + 1]; \
826                                 *out_row++ += in_row[in_offset + 2]; \
827                         } \
828                         else \
829                         { \
830                                 *out_row++ += in_row[in_offset + 1]; \
831                                 *out_row++ += in_row[in_offset + 2]; \
832                         } \
833                         if(COMPONENTS == 4) \
834                                 *out_row++ += in_row[in_offset + 3]; \
835                 } \
836         } \
837  \
838 /* Copy to output */ \
839         if(i == plugin->config.steps - 1) \
840         { \
841                 for(int j = pkg->y1; j < pkg->y2; j++) \
842                 { \
843                         TEMP *in_row = (TEMP*)plugin->accum + COMPONENTS * w * j; \
844                         TYPE *in_backup = (TYPE*)plugin->input->get_rows()[j]; \
845                         TYPE *out_row = (TYPE*)plugin->output->get_rows()[j]; \
846                         for(int k = 0; k < w; k++) \
847                         { \
848                                 if(do_r) \
849                                 { \
850                                         *out_row++ = (*in_row++ * fraction) / 0x10000; \
851                                         in_backup++; \
852                                 } \
853                                 else \
854                                 { \
855                                         *out_row++ = *in_backup++; \
856                                         in_row++; \
857                                 } \
858  \
859                                 if(DO_YUV) \
860                                 { \
861                                         if(do_g) \
862                                         { \
863                                                 *out_row++ = (*in_row++ * fraction) / 0x10000; \
864                                                 in_backup++; \
865                                         } \
866                                         else \
867                                         { \
868                                                 *out_row++ = *in_backup++; \
869                                                 in_row++; \
870                                         } \
871  \
872                                         if(do_b) \
873                                         { \
874                                                 *out_row++ = (*in_row++ * fraction) / 0x10000; \
875                                                 in_backup++; \
876                                         } \
877                                         else \
878                                         { \
879                                                 *out_row++ = *in_backup++; \
880                                                 in_row++; \
881                                         } \
882                                 } \
883                                 else \
884                                 { \
885                                         if(do_g) \
886                                         { \
887                                                 *out_row++ = (*in_row++ * fraction) / 0x10000; \
888                                                 in_backup++; \
889                                         } \
890                                         else \
891                                         { \
892                                                 *out_row++ = *in_backup++; \
893                                                 in_row++; \
894                                         } \
895  \
896                                         if(do_b) \
897                                         { \
898                                                 *out_row++ = (*in_row++ * fraction) / 0x10000; \
899                                                 in_backup++; \
900                                         } \
901                                         else \
902                                         { \
903                                                 *out_row++ = *in_backup++; \
904                                                 in_row++; \
905                                         } \
906                                 } \
907  \
908                                 if(COMPONENTS == 4) \
909                                 { \
910                                         if(do_a) \
911                                         { \
912                                                 *out_row++ = (*in_row++ * fraction) / 0x10000; \
913                                                 in_backup++; \
914                                         } \
915                                         else \
916                                         { \
917                                                 *out_row++ = *in_backup++; \
918                                                 in_row++; \
919                                         } \
920                                 } \
921                         } \
922                 } \
923         } \
924 }
925
926 void LinearBlurUnit::process_package(LoadPackage *package)
927 {
928         LinearBlurPackage *pkg = (LinearBlurPackage*)package;
929         //int h = plugin->output->get_h();
930         int w = plugin->output->get_w();
931
932         int fraction = 0x10000 / plugin->config.steps;
933         int do_r = plugin->config.r;
934         int do_g = plugin->config.g;
935         int do_b = plugin->config.b;
936         int do_a = plugin->config.a;
937         for(int i = 0; i < plugin->config.steps; i++)
938         {
939                 int *x_table = plugin->scale_x_table[i];
940                 int *y_table = plugin->scale_y_table[i];
941
942                 switch(plugin->input->get_color_model())
943                 {
944                         case BC_RGB_FLOAT:
945                                 BLEND_LAYER(3, float, float, 1, 0)
946                                 break;
947                         case BC_RGB888:
948                                 BLEND_LAYER(3, uint8_t, int, 0xff, 0)
949                                 break;
950                         case BC_RGBA_FLOAT:
951                                 BLEND_LAYER(4, float, float, 1, 0)
952                                 break;
953                         case BC_RGBA8888:
954                                 BLEND_LAYER(4, uint8_t, int, 0xff, 0)
955                                 break;
956                         case BC_RGB161616:
957                                 BLEND_LAYER(3, uint16_t, int, 0xffff, 0)
958                                 break;
959                         case BC_RGBA16161616:
960                                 BLEND_LAYER(4, uint16_t, int, 0xffff, 0)
961                                 break;
962                         case BC_YUV888:
963                                 BLEND_LAYER(3, uint8_t, int, 0xff, 1)
964                                 break;
965                         case BC_YUVA8888:
966                                 BLEND_LAYER(4, uint8_t, int, 0xff, 1)
967                                 break;
968                         case BC_YUV161616:
969                                 BLEND_LAYER(3, uint16_t, int, 0xffff, 1)
970                                 break;
971                         case BC_YUVA16161616:
972                                 BLEND_LAYER(4, uint16_t, int, 0xffff, 1)
973                                 break;
974                 }
975         }
976 }
977
978
979
980
981
982
983 LinearBlurEngine::LinearBlurEngine(LinearBlurMain *plugin,
984         int total_clients,
985         int total_packages)
986  : LoadServer(total_clients, total_packages)
987 {
988         this->plugin = plugin;
989 }
990
991 void LinearBlurEngine::init_packages()
992 {
993         for(int i = 0; i < get_total_packages(); i++)
994         {
995                 LinearBlurPackage *package = (LinearBlurPackage*)get_package(i);
996                 package->y1 = plugin->output->get_h() * i / get_total_packages();
997                 package->y2 = plugin->output->get_h() * (i + 1) / get_total_packages();
998         }
999 }
1000
1001 LoadClient* LinearBlurEngine::new_client()
1002 {
1003         return new LinearBlurUnit(this, plugin);
1004 }
1005
1006 LoadPackage* LinearBlurEngine::new_package()
1007 {
1008         return new LinearBlurPackage;
1009 }
1010
1011
1012
1013
1014