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