Credit Andrew for build mods and cineform format
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / zoomblur / zoomblur.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22
23 #include "zoomblur.h"
24
25
26
27 REGISTER_PLUGIN(ZoomBlurMain)
28
29
30
31 ZoomBlurConfig::ZoomBlurConfig()
32 {
33         reset(RESET_DEFAULT_SETTINGS);
34 }
35
36 void ZoomBlurConfig::reset(int clear)
37 {
38         switch(clear) {
39                 case RESET_ALL :
40                         x = 50;
41                         y = 50;
42                         radius = 0;
43                         steps = 1;
44                         r = 1;
45                         g = 1;
46                         b = 1;
47                         a = 1;
48                         break;
49                 case RESET_XSLIDER : x = 50;
50                         break;
51                 case RESET_YSLIDER : y = 50;
52                         break;
53                 case RESET_RADIUS : radius = 0;
54                         break;
55                 case RESET_STEPS : steps = 1;
56                         break;
57                 case RESET_DEFAULT_SETTINGS :
58                 default:
59                         x = 50;
60                         y = 50;
61                         radius = 10;
62                         steps = 10;
63                         r = 1;
64                         g = 1;
65                         b = 1;
66                         a = 1;
67                         break;
68         }
69 }
70
71 int ZoomBlurConfig::equivalent(ZoomBlurConfig &that)
72 {
73         return
74                 x == that.x &&
75                 y == that.y &&
76                 radius == that.radius &&
77                 steps == that.steps &&
78                 r == that.r &&
79                 g == that.g &&
80                 b == that.b &&
81                 a == that.a;
82 }
83
84 void ZoomBlurConfig::copy_from(ZoomBlurConfig &that)
85 {
86         x = that.x;
87         y = that.y;
88         radius = that.radius;
89         steps = that.steps;
90         r = that.r;
91         g = that.g;
92         b = that.b;
93         a = that.a;
94 }
95
96 void ZoomBlurConfig::interpolate(ZoomBlurConfig &prev,
97         ZoomBlurConfig &next,
98         long prev_frame,
99         long next_frame,
100         long current_frame)
101 {
102         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
103         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
104         this->x = (int)(prev.x * prev_scale + next.x * next_scale + 0.5);
105         this->y = (int)(prev.y * prev_scale + next.y * next_scale + 0.5);
106         this->radius = (int)(prev.radius * prev_scale + next.radius * next_scale + 0.5);
107         this->steps = (int)(prev.steps * prev_scale + next.steps * next_scale + 0.5);
108         r = prev.r;
109         g = prev.g;
110         b = prev.b;
111         a = prev.a;
112 }
113
114
115
116
117
118
119
120
121
122
123
124
125 ZoomBlurWindow::ZoomBlurWindow(ZoomBlurMain *plugin)
126  : PluginClientWindow(plugin,
127         xS(420),
128         yS(230),
129         xS(420),
130         yS(230),
131         0)
132 {
133         this->plugin = plugin;
134 }
135
136 ZoomBlurWindow::~ZoomBlurWindow()
137 {
138 }
139
140 void ZoomBlurWindow::create_objects()
141 {
142         int xs10 = xS(10), xs100 = xS(100), xs200 = xS(200);
143         int ys10 = yS(10), ys30 = yS(30), ys40 = yS(40);
144         int x = xs10, y = ys10;
145         int x2 = xS(80), x3 = xS(180);
146         int clr_x = get_w()-x - xS(22); // note: clrBtn_w = 22
147         int defaultBtn_w = xs100;
148
149         BC_Bar *bar;
150
151         y += ys10;
152         add_subwindow(new BC_Title(x, y, _("X:")));
153         x_text = new ZoomBlurIText(this, plugin,
154                 0, &plugin->config.x, (x + x2), y, XY_MIN, XY_MAX);
155         x_text->create_objects();
156         x_slider = new ZoomBlurISlider(plugin,
157                 x_text, &plugin->config.x, x3, y, XY_MIN, XY_MAX, xs200);
158         add_subwindow(x_slider);
159         x_text->slider = x_slider;
160         clr_x = x3 + x_slider->get_w() + x;
161         add_subwindow(x_Clr = new ZoomBlurClr(plugin, this, clr_x, y, RESET_XSLIDER));
162         y += ys30;
163
164         add_subwindow(new BC_Title(x, y, _("Y:")));
165         y_text = new ZoomBlurIText(this, plugin,
166                 0, &plugin->config.y, (x + x2), y, XY_MIN, XY_MAX);
167         y_text->create_objects();
168         y_slider = new ZoomBlurISlider(plugin,
169                 y_text, &plugin->config.y, x3, y, XY_MIN, XY_MAX, xs200);
170         add_subwindow(y_slider);
171         y_text->slider = y_slider;
172         add_subwindow(y_Clr = new ZoomBlurClr(plugin, this, clr_x, y, RESET_YSLIDER));
173         y += ys30;
174
175         add_subwindow(new BC_Title(x, y, _("Radius:")));
176         radius_text = new ZoomBlurIText(this, plugin,
177                 0, &plugin->config.radius, (x + x2), y, -RADIUS_MAX, RADIUS_MAX);
178         radius_text->create_objects();
179         radius_slider = new ZoomBlurISlider(plugin,
180                 radius_text, &plugin->config.radius, x3, y, -RADIUS_MAX, RADIUS_MAX, xs200);
181         add_subwindow(radius_slider);
182         radius_text->slider = radius_slider;
183         add_subwindow(radius_Clr = new ZoomBlurClr(plugin, this, clr_x, y, RESET_RADIUS));
184         y += ys30;
185
186         add_subwindow(new BC_Title(x, y, _("Steps:")));
187         steps_text = new ZoomBlurIText(this, plugin,
188                 0, &plugin->config.steps, (x + x2), y, STEPS_MIN, STEPS_MAX);
189         steps_text->create_objects();
190         steps_slider = new ZoomBlurISlider(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 ZoomBlurClr(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 ZoomBlurToggle(plugin, x1, y, &plugin->config.r, _("Red")));
202         x1 += toggle_w;
203         add_subwindow(g = new ZoomBlurToggle(plugin, x1, y, &plugin->config.g, _("Green")));
204         x1 += toggle_w;
205         add_subwindow(b = new ZoomBlurToggle(plugin, x1, y, &plugin->config.b, _("Blue")));
206         x1 += toggle_w;
207         add_subwindow(a = new ZoomBlurToggle(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 ZoomBlurReset(plugin, this, x, y));
214         add_subwindow(default_settings = new ZoomBlurDefaultSettings(plugin, this,
215                 (get_w() - xs10 - defaultBtn_w), y, defaultBtn_w));
216
217         show_window();
218         flush();
219 }
220
221 // for Reset button
222 void ZoomBlurWindow::update_gui(int clear)
223 {
224         switch(clear) {
225                 case RESET_XSLIDER :
226                         x_text->update((int64_t)plugin->config.x);
227                         x_slider->update(plugin->config.x);
228                         break;
229                 case RESET_YSLIDER :
230                         y_text->update((int64_t)plugin->config.y);
231                         y_slider->update(plugin->config.y);
232                         break;
233                 case RESET_RADIUS :
234                         radius_text->update((int64_t)plugin->config.radius);
235                         radius_slider->update(plugin->config.radius);
236                         break;
237                 case RESET_STEPS :
238                         steps_text->update((int64_t)plugin->config.steps);
239                         steps_slider->update(plugin->config.steps);
240                         break;
241                 case RESET_ALL :
242                 case RESET_DEFAULT_SETTINGS :
243                 default:
244                         x_text->update((int64_t)plugin->config.x);
245                         x_slider->update(plugin->config.x);
246                         y_text->update((int64_t)plugin->config.y);
247                         y_slider->update(plugin->config.y);
248                         radius_text->update((int64_t)plugin->config.radius);
249                         radius_slider->update(plugin->config.radius);
250                         steps_text->update((int64_t)plugin->config.steps);
251                         steps_slider->update(plugin->config.steps);
252                         r->update(plugin->config.r);
253                         g->update(plugin->config.g);
254                         b->update(plugin->config.b);
255                         a->update(plugin->config.a);
256                         break;
257         }
258 }
259
260
261
262
263
264
265
266
267
268
269 ZoomBlurToggle::ZoomBlurToggle(ZoomBlurMain *plugin,
270         int x,
271         int y,
272         int *output,
273         char *string)
274  : BC_CheckBox(x, y, *output, string)
275 {
276         this->plugin = plugin;
277         this->output = output;
278 }
279
280 int ZoomBlurToggle::handle_event()
281 {
282         *output = get_value();
283         plugin->send_configure_change();
284         return 1;
285 }
286
287
288 ZoomBlurIText::ZoomBlurIText(ZoomBlurWindow *window, ZoomBlurMain *plugin,
289         ZoomBlurISlider *slider, int *output, int x, int y, int min, int max)
290  : BC_TumbleTextBox(window, *output,
291         min, max, x, y, xS(60), 0)
292 {
293         this->window = window;
294         this->plugin = plugin;
295         this->output = output;
296         this->slider = slider;
297         this->min = min;
298         this->max = max;
299         set_increment(1);
300 }
301
302 ZoomBlurIText::~ZoomBlurIText()
303 {
304 }
305
306 int ZoomBlurIText::handle_event()
307 {
308         *output = atoi(get_text());
309         if(*output > max) *output = max;
310         if(*output < min) *output = min;
311         slider->update(*output);
312         plugin->send_configure_change();
313         return 1;
314 }
315
316
317 ZoomBlurISlider::ZoomBlurISlider(ZoomBlurMain *plugin,
318         ZoomBlurIText *text, int *output, int x, int y, int min, int max, int w)
319  : BC_ISlider(x, y, 0, w, w, min, max, *output)
320 {
321         this->plugin = plugin;
322         this->output = output;
323         this->text = text;
324         enable_show_value(0); // Hide caption
325 }
326
327 ZoomBlurISlider::~ZoomBlurISlider()
328 {
329 }
330
331 int ZoomBlurISlider::handle_event()
332 {
333         *output = get_value();
334         text->update((int64_t)*output);
335         plugin->send_configure_change();
336         return 1;
337 }
338
339
340 ZoomBlurReset::ZoomBlurReset(ZoomBlurMain *plugin, ZoomBlurWindow *window, int x, int y)
341  : BC_GenericButton(x, y, _("Reset"))
342 {
343         this->plugin = plugin;
344         this->window = window;
345 }
346 ZoomBlurReset::~ZoomBlurReset()
347 {
348 }
349 int ZoomBlurReset::handle_event()
350 {
351         plugin->config.reset(RESET_ALL);
352         window->update_gui(RESET_ALL);
353         plugin->send_configure_change();
354         return 1;
355 }
356
357
358 ZoomBlurDefaultSettings::ZoomBlurDefaultSettings(ZoomBlurMain *plugin, ZoomBlurWindow *window, int x, int y, int w)
359  : BC_GenericButton(x, y, w, _("Default"))
360 {
361         this->plugin = plugin;
362         this->window = window;
363 }
364 ZoomBlurDefaultSettings::~ZoomBlurDefaultSettings()
365 {
366 }
367 int ZoomBlurDefaultSettings::handle_event()
368 {
369         plugin->config.reset(RESET_DEFAULT_SETTINGS);
370         window->update_gui(RESET_DEFAULT_SETTINGS);
371         plugin->send_configure_change();
372         return 1;
373 }
374
375
376 ZoomBlurClr::ZoomBlurClr(ZoomBlurMain *plugin, ZoomBlurWindow *window, int x, int y, int clear)
377  : BC_Button(x, y, plugin->get_theme()->get_image_set("reset_button"))
378 {
379         this->plugin = plugin;
380         this->window = window;
381         this->clear = clear;
382 }
383 ZoomBlurClr::~ZoomBlurClr()
384 {
385 }
386 int ZoomBlurClr::handle_event()
387 {
388         // clear==1 ==> X slider
389         // clear==2 ==> Y slider
390         // clear==3 ==> Radius slider
391         // clear==4 ==> Steps slider
392         plugin->config.reset(clear);
393         window->update_gui(clear);
394         plugin->send_configure_change();
395         return 1;
396 }
397
398
399
400
401 ZoomBlurMain::ZoomBlurMain(PluginServer *server)
402  : PluginVClient(server)
403 {
404
405         engine = 0;
406         scale_x_table = 0;
407         scale_y_table = 0;
408         layer_table = 0;
409         table_entries = 0;
410         accum = 0;
411         need_reconfigure = 1;
412         temp = 0;
413 }
414
415 ZoomBlurMain::~ZoomBlurMain()
416 {
417
418         if(engine) delete engine;
419         delete_tables();
420         if(accum) delete [] accum;
421         if(temp) delete temp;
422 }
423
424 const char* ZoomBlurMain::plugin_title() { return N_("Zoom Blur"); }
425 int ZoomBlurMain::is_realtime() { return 1; }
426
427
428
429 NEW_WINDOW_MACRO(ZoomBlurMain, ZoomBlurWindow)
430
431 LOAD_CONFIGURATION_MACRO(ZoomBlurMain, ZoomBlurConfig)
432
433 void ZoomBlurMain::delete_tables()
434 {
435         if(scale_x_table)
436         {
437                 for(int i = 0; i < table_entries; i++)
438                         delete [] scale_x_table[i];
439                 delete [] scale_x_table;
440         }
441
442         if(scale_y_table)
443         {
444                 for(int i = 0; i < table_entries; i++)
445                         delete [] scale_y_table[i];
446                 delete [] scale_y_table;
447         }
448
449         delete [] layer_table;
450         scale_x_table = 0;
451         scale_y_table = 0;
452         layer_table = 0;
453         table_entries = 0;
454 }
455
456 int ZoomBlurMain::process_buffer(VFrame *frame,
457                 int64_t start_position,
458                 double frame_rate)
459 {
460         need_reconfigure |= load_configuration();
461
462
463 SET_TRACE
464         read_frame(frame,
465                 0,
466                 get_source_position(),
467                 get_framerate(),
468                 get_use_opengl());
469
470 SET_TRACE
471
472 // Generate tables here.  The same table is used by many packages to render
473 // each horizontal stripe.  Need to cover the entire output range in  each
474 // table to avoid green borders
475         if(need_reconfigure)
476         {
477 SET_TRACE
478                 float w = frame->get_w();
479                 float h = frame->get_h();
480                 float center_x = (float)config.x / 100 * w;
481                 float center_y = (float)config.y / 100 * h;
482                 float radius = (float)(100 + config.radius) / 100;
483                 float min_w, min_h;
484                 //float max_w, max_h;
485                 int steps = config.steps ? config.steps : 1;
486                 float min_x1;
487                 float min_y1;
488                 float min_x2;
489                 float min_y2;
490                 float max_x1;
491                 float max_y1;
492                 float max_x2;
493                 float max_y2;
494
495 SET_TRACE
496
497 // printf("ZoomBlurMain::process_realtime 1 %d %d\n",
498 // config.x,
499 // config.y);
500
501                 center_x = (center_x - w / 2) * (1.0 - radius) + w / 2;
502                 center_y = (center_y - h / 2) * (1.0 - radius) + h / 2;
503                 min_w = w * radius;
504                 min_h = h * radius;
505                 //max_w = w;
506                 //max_h = h;
507                 min_x1 = center_x - min_w / 2;
508                 min_y1 = center_y - min_h / 2;
509                 min_x2 = center_x + min_w / 2;
510                 min_y2 = center_y + min_h / 2;
511                 max_x1 = 0;
512                 max_y1 = 0;
513                 max_x2 = w;
514                 max_y2 = h;
515
516 SET_TRACE
517 // printf("ZoomBlurMain::process_realtime 2 w=%f radius=%f center_x=%f\n",
518 // w,
519 // radius,
520 // center_x);
521
522
523 // Dimensions of outermost rectangle
524
525                 delete_tables();
526                 table_entries = steps;
527                 scale_x_table = new int*[steps];
528                 scale_y_table = new int*[steps];
529                 layer_table = new ZoomBlurLayer[table_entries];
530
531 SET_TRACE
532                 for(int i = 0; i < steps; i++)
533                 {
534                         float fraction = (float)i / steps;
535                         float inv_fraction = 1.0 - fraction;
536                         float out_x1 = min_x1 * fraction + max_x1 * inv_fraction;
537                         float out_x2 = min_x2 * fraction + max_x2 * inv_fraction;
538                         float out_y1 = min_y1 * fraction + max_y1 * inv_fraction;
539                         float out_y2 = min_y2 * fraction + max_y2 * inv_fraction;
540                         float out_w = out_x2 - out_x1;
541                         float out_h = out_y2 - out_y1;
542                         if(out_w < 0) out_w = 0;
543                         if(out_h < 0) out_h = 0;
544                         float scale_x = (float)w / out_w;
545                         float scale_y = (float)h / out_h;
546
547                         int *x_table;
548                         int *y_table;
549                         scale_y_table[i] = y_table = new int[(int)(h + 1)];
550                         scale_x_table[i] = x_table = new int[(int)(w + 1)];
551 SET_TRACE
552                         layer_table[i].x1 = out_x1;
553                         layer_table[i].y1 = out_y1;
554                         layer_table[i].x2 = out_x2;
555                         layer_table[i].y2 = out_y2;
556 SET_TRACE
557
558                         for(int j = 0; j < h; j++)
559                         {
560                                 y_table[j] = (int)((j - out_y1) * scale_y);
561                         }
562                         for(int j = 0; j < w; j++)
563                         {
564                                 x_table[j] = (int)((j - out_x1) * scale_x);
565 //printf("ZoomBlurMain::process_realtime %d %d\n", j, x_table[j]);
566                         }
567                 }
568 SET_TRACE
569                 need_reconfigure = 0;
570         }
571
572 SET_TRACE
573         if(get_use_opengl()) return run_opengl();
574
575 SET_TRACE
576
577
578
579         if(!engine) engine = new ZoomBlurEngine(this,
580                 get_project_smp() + 1,
581                 get_project_smp() + 1);
582         if(!accum) accum = new unsigned char[frame->get_w() *
583                 frame->get_h() *
584                 BC_CModels::components(frame->get_color_model()) *
585                 MAX(sizeof(int), sizeof(float))];
586
587         this->input = frame;
588         this->output = frame;
589
590
591         if(!temp) temp = new VFrame(frame->get_w(), frame->get_h(),
592                 frame->get_color_model(), 0);
593         temp->copy_from(frame);
594         this->input = temp;
595
596         bzero(accum,
597                 frame->get_w() *
598                 frame->get_h() *
599                 BC_CModels::components(frame->get_color_model()) *
600                 MAX(sizeof(int), sizeof(float)));
601         engine->process_packages();
602         return 0;
603 }
604
605
606 void ZoomBlurMain::update_gui()
607 {
608         if(thread)
609         {
610                 load_configuration();
611                 thread->window->lock_window();
612                 ((ZoomBlurWindow*)thread->window)->x_text->update((int64_t)config.x);
613                 ((ZoomBlurWindow*)thread->window)->x_slider->update(config.x);
614                 ((ZoomBlurWindow*)thread->window)->y_text->update((int64_t)config.y);
615                 ((ZoomBlurWindow*)thread->window)->y_slider->update(config.y);
616                 ((ZoomBlurWindow*)thread->window)->radius_text->update((int64_t)config.radius);
617                 ((ZoomBlurWindow*)thread->window)->radius_slider->update(config.radius);
618                 ((ZoomBlurWindow*)thread->window)->steps_text->update((int64_t)config.steps);
619                 ((ZoomBlurWindow*)thread->window)->steps_slider->update(config.steps);
620                 ((ZoomBlurWindow*)thread->window)->r->update(config.r);
621                 ((ZoomBlurWindow*)thread->window)->g->update(config.g);
622                 ((ZoomBlurWindow*)thread->window)->b->update(config.b);
623                 ((ZoomBlurWindow*)thread->window)->a->update(config.a);
624                 thread->window->unlock_window();
625         }
626 }
627
628
629
630
631
632 void ZoomBlurMain::save_data(KeyFrame *keyframe)
633 {
634         FileXML output;
635
636 // cause data to be stored directly in text
637         output.set_shared_output(keyframe->xbuf);
638         output.tag.set_title("ZOOMBLUR");
639
640         output.tag.set_property("X", config.x);
641         output.tag.set_property("Y", config.y);
642         output.tag.set_property("RADIUS", config.radius);
643         output.tag.set_property("STEPS", config.steps);
644         output.tag.set_property("R", config.r);
645         output.tag.set_property("G", config.g);
646         output.tag.set_property("B", config.b);
647         output.tag.set_property("A", config.a);
648         output.append_tag();
649         output.tag.set_title("/ZOOMBLUR");
650         output.append_tag();
651         output.append_newline();
652         output.terminate_string();
653 }
654
655 void ZoomBlurMain::read_data(KeyFrame *keyframe)
656 {
657         FileXML input;
658
659         input.set_shared_input(keyframe->xbuf);
660
661         int result = 0;
662
663         while(!result)
664         {
665                 result = input.read_tag();
666
667                 if(!result)
668                 {
669                         if(input.tag.title_is("ZOOMBLUR"))
670                         {
671                                 config.x = input.tag.get_property("X", config.x);
672                                 config.y = input.tag.get_property("Y", config.y);
673                                 config.radius = input.tag.get_property("RADIUS", config.radius);
674                                 config.steps = input.tag.get_property("STEPS", config.steps);
675                                 config.r = input.tag.get_property("R", config.r);
676                                 config.g = input.tag.get_property("G", config.g);
677                                 config.b = input.tag.get_property("B", config.b);
678                                 config.a = input.tag.get_property("A", config.a);
679                         }
680                 }
681         }
682 }
683
684 #ifdef HAVE_GL
685 static void draw_box(float x1, float y1, float x2, float y2)
686 {
687         glBegin(GL_QUADS);
688         glVertex3f(x1, y1, 0.0);
689         glVertex3f(x2, y1, 0.0);
690         glVertex3f(x2, y2, 0.0);
691         glVertex3f(x1, y2, 0.0);
692         glEnd();
693 }
694 #endif
695
696 int ZoomBlurMain::handle_opengl()
697 {
698 #ifdef HAVE_GL
699         get_output()->to_texture();
700         get_output()->enable_opengl();
701         get_output()->init_screen();
702         get_output()->bind_texture(0);
703
704         //int is_yuv = BC_CModels::is_yuv(get_output()->get_color_model());
705         glClearColor(0.0, 0.0, 0.0, 0.0);
706         glClear(GL_COLOR_BUFFER_BIT);
707
708 // Draw unselected channels
709         glEnable(GL_BLEND);
710         glBlendFunc(GL_ONE, GL_ONE);
711         glDrawBuffer(GL_BACK);
712
713         if(!config.r || !config.g || !config.b || !config.a)
714         {
715                 glColor4f(config.r ? 0 : 1,
716                         config.g ? 0 : 1,
717                         config.b ? 0 : 1,
718                         config.a ? 0 : 1);
719                 get_output()->draw_texture();
720         }
721         glAccum(GL_LOAD, 1.0);
722
723 // Blur selected channels
724         float fraction = 1.0 / config.steps;
725         for(int i = 0; i < config.steps; i++)
726         {
727                 glClear(GL_COLOR_BUFFER_BIT);
728                 glColor4f(config.r ? 1 : 0,
729                         config.g ? 1 : 0,
730                         config.b ? 1 : 0,
731                         config.a ? 1 : 0);
732
733                 get_output()->draw_texture(0,
734                         0,
735                         get_output()->get_w(),
736                         get_output()->get_h(),
737                         layer_table[i].x1,
738                         get_output()->get_h() - layer_table[i].y1,
739                         layer_table[i].x2,
740                         get_output()->get_h() - layer_table[i].y2,
741                         1);
742
743 // Fill YUV black
744                 glDisable(GL_TEXTURE_2D);
745                 if(BC_CModels::is_yuv(get_output()->get_color_model()))
746                 {
747                         glColor4f(config.r ? 0.0 : 0,
748                                 config.g ? 0.5 : 0,
749                                 config.b ? 0.5 : 0,
750                                 config.a ? 1.0 : 0);
751                         float center_x1 = 0.0;
752                         float center_x2 = get_output()->get_w();
753                         if(layer_table[i].x1 > 0)
754                         {
755                                 center_x1 = layer_table[i].x1;
756                                 draw_box(0, 0, layer_table[i].x1, -get_output()->get_h());
757                         }
758                         if(layer_table[i].x2 < get_output()->get_w())
759                         {
760                                 center_x2 = layer_table[i].x2;
761                                 draw_box(layer_table[i].x2, 0, get_output()->get_w(), -get_output()->get_h());
762                         }
763                         if(layer_table[i].y1 > 0)
764                         {
765                                 draw_box(center_x1,
766                                         -get_output()->get_h(),
767                                         center_x2,
768                                         -get_output()->get_h() + layer_table[i].y1);
769                         }
770                         if(layer_table[i].y2 < get_output()->get_h())
771                         {
772                                 draw_box(center_x1,
773                                         -get_output()->get_h() + layer_table[i].y2,
774                                         center_x2,
775                                         0);
776                         }
777                 }
778
779
780                 glAccum(GL_ACCUM, fraction);
781                 glEnable(GL_TEXTURE_2D);
782                 glColor4f(config.r ? 1 : 0,
783                         config.g ? 1 : 0,
784                         config.b ? 1 : 0,
785                         config.a ? 1 : 0);
786         }
787
788         glDisable(GL_BLEND);
789         glReadBuffer(GL_BACK);
790         glDisable(GL_TEXTURE_2D);
791         glAccum(GL_RETURN, 1.0);
792
793         glColor4f(1, 1, 1, 1);
794         get_output()->set_opengl_state(VFrame::SCREEN);
795 #endif
796         return 0;
797 }
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812 ZoomBlurPackage::ZoomBlurPackage()
813  : LoadPackage()
814 {
815 }
816
817
818
819
820 ZoomBlurUnit::ZoomBlurUnit(ZoomBlurEngine *server,
821         ZoomBlurMain *plugin)
822  : LoadClient(server)
823 {
824         this->plugin = plugin;
825         this->server = server;
826 }
827
828
829 #define BLEND_LAYER(COMPONENTS, TYPE, TEMP_TYPE, MAX, DO_YUV) \
830 { \
831         const int chroma_offset = (DO_YUV ? ((MAX + 1) / 2) : 0); \
832         for(int j = pkg->y1; j < pkg->y2; j++) \
833         { \
834                 TEMP_TYPE *out_row = (TEMP_TYPE*)plugin->accum + COMPONENTS * w * j; \
835                 int in_y = y_table[j]; \
836  \
837 /* Blend image */ \
838                 if(in_y >= 0 && in_y < h) \
839                 { \
840                         TYPE *in_row = (TYPE*)plugin->input->get_rows()[in_y]; \
841                         for(int k = 0; k < w; k++) \
842                         { \
843                                 int in_x = x_table[k]; \
844 /* Blend pixel */ \
845                                 if(in_x >= 0 && in_x < w) \
846                                 { \
847                                         int in_offset = in_x * COMPONENTS; \
848                                         *out_row++ += in_row[in_offset]; \
849                                         if(DO_YUV) \
850                                         { \
851                                                 *out_row++ += in_row[in_offset + 1]; \
852                                                 *out_row++ += in_row[in_offset + 2]; \
853                                         } \
854                                         else \
855                                         { \
856                                                 *out_row++ += (TEMP_TYPE)in_row[in_offset + 1]; \
857                                                 *out_row++ += (TEMP_TYPE)in_row[in_offset + 2]; \
858                                         } \
859                                         if(COMPONENTS == 4) \
860                                                 *out_row++ += in_row[in_offset + 3]; \
861                                 } \
862 /* Blend nothing */ \
863                                 else \
864                                 { \
865                                         out_row++; \
866                                         if(DO_YUV) \
867                                         { \
868                                                 *out_row++ += chroma_offset; \
869                                                 *out_row++ += chroma_offset; \
870                                         } \
871                                         else \
872                                         { \
873                                                 out_row += 2; \
874                                         } \
875                                         if(COMPONENTS == 4) out_row++; \
876                                 } \
877                         } \
878                 } \
879                 else \
880                 if(DO_YUV) \
881                 { \
882                         for(int k = 0; k < w; k++) \
883                         { \
884                                 out_row++; \
885                                 *out_row++ += chroma_offset; \
886                                 *out_row++ += chroma_offset; \
887                                 if(COMPONENTS == 4) out_row++; \
888                         } \
889                 } \
890         } \
891  \
892 /* Copy just selected blurred channels to output and combine with original \
893         unblurred channels */ \
894         if(i == plugin->config.steps - 1) \
895         { \
896                 for(int j = pkg->y1; j < pkg->y2; j++) \
897                 { \
898                         TEMP_TYPE *in_row = (TEMP_TYPE*)plugin->accum + COMPONENTS * w * j; \
899                         TYPE *in_backup = (TYPE*)plugin->input->get_rows()[j]; \
900                         TYPE *out_row = (TYPE*)plugin->output->get_rows()[j]; \
901                         for(int k = 0; k < w; k++) \
902                         { \
903                                 if(do_r) \
904                                 { \
905                                         *out_row++ = (*in_row++ * fraction) / 0x10000; \
906                                         in_backup++; \
907                                 } \
908                                 else \
909                                 { \
910                                         *out_row++ = *in_backup++; \
911                                         in_row++; \
912                                 } \
913  \
914                                 if(DO_YUV) \
915                                 { \
916                                         if(do_g) \
917                                         { \
918                                                 *out_row++ = ((*in_row++ * fraction) / 0x10000); \
919                                                 in_backup++; \
920                                         } \
921                                         else \
922                                         { \
923                                                 *out_row++ = *in_backup++; \
924                                                 in_row++; \
925                                         } \
926  \
927                                         if(do_b) \
928                                         { \
929                                                 *out_row++ = ((*in_row++ * fraction) / 0x10000); \
930                                                 in_backup++; \
931                                         } \
932                                         else \
933                                         { \
934                                                 *out_row++ = *in_backup++; \
935                                                 in_row++; \
936                                         } \
937                                 } \
938                                 else \
939                                 { \
940                                         if(do_g) \
941                                         { \
942                                                 *out_row++ = (*in_row++ * fraction) / 0x10000; \
943                                                 in_backup++; \
944                                         } \
945                                         else \
946                                         { \
947                                                 *out_row++ = *in_backup++; \
948                                                 in_row++; \
949                                         } \
950  \
951                                         if(do_b) \
952                                         { \
953                                                 *out_row++ = (*in_row++ * fraction) / 0x10000; \
954                                                 in_backup++; \
955                                         } \
956                                         else \
957                                         { \
958                                                 *out_row++ = *in_backup++; \
959                                                 in_row++; \
960                                         } \
961                                 } \
962  \
963                                 if(COMPONENTS == 4) \
964                                 { \
965                                         if(do_a) \
966                                         { \
967                                                 *out_row++ = (*in_row++ * fraction) / 0x10000; \
968                                                 in_backup++; \
969                                         } \
970                                         else \
971                                         { \
972                                                 *out_row++ = *in_backup++; \
973                                                 in_row++; \
974                                         } \
975                                 } \
976                         } \
977                 } \
978         } \
979 }
980
981 void ZoomBlurUnit::process_package(LoadPackage *package)
982 {
983         ZoomBlurPackage *pkg = (ZoomBlurPackage*)package;
984         int h = plugin->output->get_h();
985         int w = plugin->output->get_w();
986         int do_r = plugin->config.r;
987         int do_g = plugin->config.g;
988         int do_b = plugin->config.b;
989         int do_a = plugin->config.a;
990
991         int fraction = 0x10000 / plugin->config.steps;
992         for(int i = 0; i < plugin->config.steps; i++)
993         {
994                 int *x_table = plugin->scale_x_table[i];
995                 int *y_table = plugin->scale_y_table[i];
996
997                 switch(plugin->input->get_color_model())
998                 {
999                         case BC_RGB888:
1000                                 BLEND_LAYER(3, uint8_t, int, 0xff, 0)
1001                                 break;
1002                         case BC_RGB_FLOAT:
1003                                 BLEND_LAYER(3, float, float, 1, 0)
1004                                 break;
1005                         case BC_RGBA_FLOAT:
1006                                 BLEND_LAYER(4, float, float, 1, 0)
1007                                 break;
1008                         case BC_RGBA8888:
1009                                 BLEND_LAYER(4, uint8_t, int, 0xff, 0)
1010                                 break;
1011                         case BC_RGB161616:
1012                                 BLEND_LAYER(3, uint16_t, int, 0xffff, 0)
1013                                 break;
1014                         case BC_RGBA16161616:
1015                                 BLEND_LAYER(4, uint16_t, int, 0xffff, 0)
1016                                 break;
1017                         case BC_YUV888:
1018                                 BLEND_LAYER(3, uint8_t, int, 0xff, 1)
1019                                 break;
1020                         case BC_YUVA8888:
1021                                 BLEND_LAYER(4, uint8_t, int, 0xff, 1)
1022                                 break;
1023                         case BC_YUV161616:
1024                                 BLEND_LAYER(3, uint16_t, int, 0xffff, 1)
1025                                 break;
1026                         case BC_YUVA16161616:
1027                                 BLEND_LAYER(4, uint16_t, int, 0xffff, 1)
1028                                 break;
1029                 }
1030         }
1031 }
1032
1033
1034
1035
1036
1037
1038 ZoomBlurEngine::ZoomBlurEngine(ZoomBlurMain *plugin,
1039         int total_clients,
1040         int total_packages)
1041  : LoadServer(total_clients, total_packages)
1042 {
1043         this->plugin = plugin;
1044 }
1045
1046 void ZoomBlurEngine::init_packages()
1047 {
1048         for(int i = 0; i < get_total_packages(); i++)
1049         {
1050                 ZoomBlurPackage *package = (ZoomBlurPackage*)get_package(i);
1051                 package->y1 = plugin->output->get_h() * i / get_total_packages();
1052                 package->y2 = plugin->output->get_h() * (i + 1) / get_total_packages();
1053         }
1054 }
1055
1056 LoadClient* ZoomBlurEngine::new_client()
1057 {
1058         return new ZoomBlurUnit(this, plugin);
1059 }
1060
1061 LoadPackage* ZoomBlurEngine::new_package()
1062 {
1063         return new ZoomBlurPackage;
1064 }
1065
1066
1067
1068
1069