0cd3bbe002b7249ac6d4be345dff6f057a647d65
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / shapewipe / shapewipe.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include "bcdisplayinfo.h"
23 #include "bchash.h"
24 #include "cstrdup.h"
25 #include "edl.inc"
26 #include "filesystem.h"
27 #include "filexml.h"
28 #include "language.h"
29 #include "overlayframe.h"
30 #include "theme.h"
31 #include "vframe.h"
32 #include "shapewipe.h"
33
34 #include <png.h>
35 #include <math.h>
36 #include <stdint.h>
37 #include <string.h>
38
39 #define SHAPE_SEARCHPATH "/shapes"
40 #define DEFAULT_SHAPE "circle"
41 // feather slider range log2 = -10 .. -1 == 9.8e-4 .. 0.5
42 #define SHAPE_FLOG_MIN -10.
43 #define SHAPE_FLOG_MAX -1.
44 #define SHAPE_FMIN expf(M_LN2*SHAPE_FLOG_MIN)
45 #define SHAPE_FMAX expf(M_LN2*SHAPE_FLOG_MAX)
46
47 REGISTER_PLUGIN(ShapeWipeMain)
48
49 ShapeWipeConfig::ShapeWipeConfig()
50 {
51         direction = 0;
52         feather = SHAPE_FMIN;
53         preserve_aspect = 0;
54         strcpy(shape_name, DEFAULT_SHAPE);
55 }
56 ShapeWipeConfig::~ShapeWipeConfig()
57 {
58 }
59
60 void ShapeWipeConfig::read_xml(KeyFrame *keyframe)
61 {
62         FileXML input;
63         input.set_shared_input(keyframe->xbuf);
64
65         while( !input.read_tag() ) {
66                 if( input.tag.title_is("SHAPEWIPE") ) {
67                         direction = input.tag.get_property("DIRECTION", direction);
68                         feather = input.tag.get_property("FEATHER", feather);
69                         preserve_aspect = input.tag.get_property("PRESERVE_ASPECT", preserve_aspect);
70                         input.tag.get_property("SHAPE_NAME", shape_name);
71                 }
72         }
73 }
74 void ShapeWipeConfig::save_xml(KeyFrame *keyframe)
75 {
76         FileXML output;
77         output.set_shared_output(keyframe->xbuf);
78         output.tag.set_title("SHAPEWIPE");
79         output.tag.set_property("DIRECTION", direction);
80         output.tag.set_property("FEATHER", feather);
81         output.tag.set_property("PRESERVE_ASPECT", preserve_aspect);
82         output.tag.set_property("SHAPE_NAME", shape_name);
83         output.append_tag();
84         output.tag.set_title("/SHAPEWIPE");
85         output.append_tag();
86         output.terminate_string();
87 }
88
89
90 ShapeWipeW2B::ShapeWipeW2B(ShapeWipeMain *plugin,
91         ShapeWipeWindow *window, int x, int y)
92  : BC_Radial(x, y, plugin->config.direction == 0, _("White to Black"))
93 {
94         this->plugin = plugin;
95         this->window = window;
96 }
97
98 int ShapeWipeW2B::handle_event()
99 {
100         update(1);
101         plugin->config.direction = 0;
102         window->right->update(0);
103         plugin->send_configure_change();
104         return 0;
105 }
106
107 ShapeWipeB2W::ShapeWipeB2W(ShapeWipeMain *plugin,
108         ShapeWipeWindow *window, int x, int y)
109  : BC_Radial(x, y, plugin->config.direction == 1, _("Black to White"))
110 {
111         this->plugin = plugin;
112         this->window = window;
113 }
114
115 int ShapeWipeB2W::handle_event()
116 {
117         update(1);
118         plugin->config.direction = 1;
119         window->left->update(0);
120         plugin->send_configure_change();
121         return 0;
122 }
123
124
125 ShapeWipePreserveAspectRatio::ShapeWipePreserveAspectRatio(ShapeWipeMain *plugin,
126         ShapeWipeWindow *window, int x, int y)
127  : BC_CheckBox (x, y, plugin->config.preserve_aspect, _("Preserve shape aspect ratio"))
128 {
129         this->plugin = plugin;
130         this->window = window;
131 }
132
133 int ShapeWipePreserveAspectRatio::handle_event()
134 {
135         plugin->config.preserve_aspect = get_value();
136         plugin->send_configure_change();
137         return 0;
138 }
139
140
141 ShapeWipeTumble::ShapeWipeTumble(ShapeWipeMain *client,
142         ShapeWipeWindow *window, int x, int y)
143  : BC_Tumbler(x, y)
144 {
145         this->client = client;
146         this->window = window;
147         set_increment(0.01);
148 }
149
150 int ShapeWipeTumble::handle_up_event()
151 {
152         window->prev_shape();
153         return 1;
154 }
155
156 int ShapeWipeTumble::handle_down_event()
157 {
158         window->next_shape();
159         return 0;
160 }
161
162
163 ShapeWipeFeather::ShapeWipeFeather(ShapeWipeMain *client,
164                 ShapeWipeWindow *window, int x, int y)
165  : BC_TumbleTextBox(window,
166                 bclip(client->config.feather, SHAPE_FMIN, SHAPE_FMAX),
167                 SHAPE_FMIN, SHAPE_FMAX, x, y, 64, 3)
168 {
169         this->client = client;
170         this->window = window;
171 }
172
173 int ShapeWipeFeather::handle_event()
174 {
175         float v = atof(get_text());
176         bclamp(v, SHAPE_FMIN, SHAPE_FMAX);
177         client->config.feather = v;
178         float sv = log(v)/M_LN2;
179         window->shape_fslider->update(sv);
180         client->send_configure_change();
181         return 1;
182 }
183
184 ShapeWipeFSlider::ShapeWipeFSlider(ShapeWipeMain *client,
185                 ShapeWipeWindow *window, int x, int y, int w)
186  : BC_FSlider(x, y, 0, w, w, SHAPE_FLOG_MIN, SHAPE_FLOG_MAX,
187         log(bclip(client->config.feather, SHAPE_FMIN, SHAPE_FMAX))/M_LN2)
188 {
189         this->client = client;
190         this->window = window;
191         set_precision(0.001);
192         set_pagination(0.01, 0.1);
193         enable_show_value(0);
194 }
195
196 int ShapeWipeFSlider::handle_event()
197 {
198         float v = get_value();
199         float vv = exp(M_LN2*v);
200         client->config.feather = vv;
201         window->shape_feather->update(vv);
202         client->send_configure_change();
203         return 1;
204 }
205
206 ShapeWipeReset::ShapeWipeReset(ShapeWipeMain *client,
207                 ShapeWipeWindow *window, int x, int y)
208  : BC_Button(x, y, client->get_theme()->get_image_set("reset_button"))
209 {
210         this->client = client;
211         this->window = window;
212         set_tooltip(_("Reset feather"));
213 }
214
215 int ShapeWipeReset::handle_event()
216 {
217         window->shape_fslider->update(SHAPE_FLOG_MIN);
218         float v = SHAPE_FMIN;
219         window->shape_feather->update(v);
220         client->config.feather = v;
221         client->send_configure_change();
222         return 1;
223 }
224
225 int ShapeWipeReset::calculate_w(ShapeWipeMain *client)
226 {
227         VFrame **reset_images = client->get_theme()->get_image_set("reset_button");
228         return reset_images[0]->get_w();
229 }
230
231
232 ShapeWipeShape::ShapeWipeShape(ShapeWipeMain *client,
233                 ShapeWipeWindow *window, int x, int y,
234                 int text_w, int list_h)
235  : BC_PopupTextBox(window, &window->shapes, client->config.shape_name,
236         x, y, text_w, list_h)
237 {
238         this->client = client;
239         this->window = window;
240 }
241
242 int ShapeWipeShape::handle_event()
243 {
244         strcpy(client->config.shape_name, get_text());
245         client->send_configure_change();
246         return 1;
247 }
248
249
250 ShapeWipeWindow::ShapeWipeWindow(ShapeWipeMain *plugin)
251  : PluginClientWindow(plugin, 425, 215, 425, 215, 0)
252 {
253         this->plugin = plugin;
254         shape_feather = 0;
255 }
256
257 ShapeWipeWindow::~ShapeWipeWindow()
258 {
259         shapes.remove_all_objects();
260         delete shape_feather;
261 }
262
263
264 void ShapeWipeWindow::create_objects()
265 {
266         BC_Title *title = 0;
267         lock_window("ShapeWipeWindow::create_objects");
268         int pad = 10, margin = 10;
269         int x = margin, y = margin;
270         int ww = get_w() - 2*margin;
271
272         plugin->init_shapes();
273         for( int i=0; i<plugin->shape_titles.size(); ++i ) {
274                 shapes.append(new BC_ListBoxItem(plugin->shape_titles.get(i)));
275         }
276
277         BC_TitleBar *bar;
278         add_subwindow(bar = new BC_TitleBar(x, y, ww, x+ww/12,
279                 pad, _("Wipe"), MEDIUMFONT));
280         y += bar->get_h() + pad;
281
282         add_subwindow(title = new BC_Title(x, y, _("Shape:")));
283         int x1 = get_w()/5;
284         x = x1;
285         int tw = ww - x1 - ShapeWipeTumble::calculate_w() - pad -
286                 BC_WindowBase::get_resources()->listbox_button[0]->get_w();
287         shape_text = new ShapeWipeShape(plugin, this, x1, y, tw, 200);
288         shape_text->create_objects();
289         x += shape_text->get_w() + pad;
290         add_subwindow(new ShapeWipeTumble(plugin,
291                 this, x, y));
292         y += shape_text->get_h() + pad;
293
294         x = margin;
295         add_subwindow(title = new BC_Title(x, y, _("Feather:")));
296         x = x1;
297         shape_feather = new ShapeWipeFeather(plugin, this, x, y);
298         shape_feather->create_objects();
299         shape_feather->set_log_floatincrement(1);
300         x += shape_feather->get_w() + 2*pad;
301         int sw = ww - ShapeWipeReset::calculate_w(plugin) - pad - x;
302         add_subwindow(shape_fslider = new ShapeWipeFSlider(plugin, this, x, y, sw));
303         x += shape_fslider->get_w() + 2*pad;
304         add_subwindow(shape_reset = new ShapeWipeReset(plugin, this, x, y));
305         y += shape_fslider->get_h() + pad;
306
307         x = margin;
308         ShapeWipePreserveAspectRatio *aspect_ratio;
309         add_subwindow(aspect_ratio = new ShapeWipePreserveAspectRatio(
310                 plugin, this, x, y));
311         y += aspect_ratio->get_h() + pad;
312
313         add_subwindow(bar = new BC_TitleBar(x, y, ww, x+ww/12,
314                 pad, _("Direction"), MEDIUMFONT));
315         y += bar->get_h() + pad;
316         x = margin;
317         add_subwindow(left = new ShapeWipeW2B(plugin, this, x, y));
318         y += left->get_h();
319         add_subwindow(right = new ShapeWipeB2W(plugin, this, x, y));
320
321         show_window();
322         unlock_window();
323 }
324
325 void ShapeWipeWindow::next_shape()
326 {
327         ShapeWipeConfig &config = plugin->config;
328         int k = plugin->shape_titles.size();
329         while( --k>=0 && strcmp(plugin->shape_titles.get(k),config.shape_name) );
330
331         if( k >= 0 ) {
332                 if( ++k >= plugin->shape_titles.size() ) k = 0;
333                 strcpy(config.shape_name, plugin->shape_titles.get(k));
334                 shape_text->update(config.shape_name);
335         }
336         client->send_configure_change();
337 }
338
339 void ShapeWipeWindow::prev_shape()
340 {
341         ShapeWipeConfig &config = plugin->config;
342         int k = plugin->shape_titles.size();
343         while( --k>=0 && strcmp(plugin->shape_titles.get(k),config.shape_name) );
344
345         if( k >= 0 ) {
346                 if( --k < 0 ) k = plugin->shape_titles.size()-1;
347                 strcpy(config.shape_name, plugin->shape_titles.get(k));
348                 shape_text->update(config.shape_name);
349         }
350         client->send_configure_change();
351 }
352
353
354 ShapeWipeMain::ShapeWipeMain(PluginServer *server)
355  : PluginVClient(server)
356 {
357         input = 0;
358         output = 0;
359         engine = 0;
360         current_filename[0] = '\0';
361         current_name[0] = 0;
362         pattern_image = 0;
363         min_value = 255;
364         max_value = 0;
365         last_preserve_aspect = 0;
366         shapes_initialized = 0;
367         shape_paths.set_array_delete();
368         shape_titles.set_array_delete();
369 }
370
371 ShapeWipeMain::~ShapeWipeMain()
372 {
373         reset_pattern_image();
374         shape_paths.remove_all_objects();
375         shape_titles.remove_all_objects();
376         delete engine;
377 }
378
379 const char* ShapeWipeMain::plugin_title() { return N_("Shape Wipe"); }
380 int ShapeWipeMain::is_transition() { return 1; }
381 int ShapeWipeMain::uses_gui() { return 1; }
382
383 NEW_WINDOW_MACRO(ShapeWipeMain, ShapeWipeWindow);
384
385 void ShapeWipeMain::read_data(KeyFrame *keyframe)
386 {
387         config.read_xml(keyframe);
388 }
389 void ShapeWipeMain::save_data(KeyFrame *keyframe)
390 {
391         config.save_xml(keyframe);
392 }
393
394 void ShapeWipeMain::init_shapes()
395 {
396         if( !shapes_initialized ) {
397                 FileSystem fs;
398                 fs.set_filter("*.png");
399                 char shape_path[BCTEXTLEN];
400                 sprintf(shape_path, "%s%s", get_plugin_dir(), SHAPE_SEARCHPATH);
401                 fs.update(shape_path);
402
403                 for( int i=0; i<fs.total_files(); ++i ) {
404                         FileItem *file_item = fs.get_entry(i);
405                         if( !file_item->get_is_dir() ) {
406                                 shape_paths.append(cstrdup(file_item->get_path()));
407                                 char *ptr = cstrdup(file_item->get_name());
408                                 char *ptr2 = strrchr(ptr, '.');
409                                 if(ptr2) *ptr2 = 0;
410                                 shape_titles.append(ptr);
411                         }
412                 }
413
414                 shapes_initialized = 1;
415         }
416 }
417
418
419 int ShapeWipeMain::load_configuration()
420 {
421         read_data(get_prev_keyframe(get_source_position()));
422         return 1;
423 }
424
425 int ShapeWipeMain::read_pattern_image(char *shape_name,
426                 int new_frame_width, int new_frame_height)
427 {
428         png_byte header[8];
429         int is_png;
430         int row, col;
431         int pixel_width;
432         unsigned char value;
433         png_uint_32 width;
434         png_uint_32 height;
435         png_byte color_type;
436         png_byte bit_depth;
437         png_structp png_ptr = 0;
438         png_infop info_ptr = 0;
439         png_infop end_info = 0;
440         png_bytep *image = 0;
441         FILE *fp = 0;
442         frame_width = new_frame_width;
443         frame_height = new_frame_height;
444         int ret = 0;
445
446 // Convert name to filename
447         int k = shape_paths.size();
448         while( --k>=0 && strcmp(shape_titles[k], shape_name) );
449         if( k < 0 ) ret = 1;
450         if( !ret ) {
451                 strcpy(current_filename, shape_paths[k]);
452                 fp = fopen(current_filename, "rb");
453                 if( !fp ) ret = 1;
454         }
455         if( !ret ) {
456                 fread(header, 1, 8, fp);
457                 is_png = !png_sig_cmp(header, 0, 8);
458                 if( !is_png ) ret = 1;
459         }
460         if( !ret ) {
461                 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
462                 if( !png_ptr ) ret = 1;
463         }
464         if( !ret ) {
465                 /* Tell libpng we already checked the first 8 bytes */
466                 png_set_sig_bytes(png_ptr, 8);
467                 info_ptr = png_create_info_struct(png_ptr);
468                 if( !info_ptr ) ret = 1;
469         }
470         if( !ret ) {
471                 end_info = png_create_info_struct(png_ptr);
472                 if( !end_info ) ret = 1;
473         }
474         if( !ret ) {
475                 png_init_io(png_ptr, fp);
476                 png_read_info(png_ptr, info_ptr);
477
478                 color_type = png_get_color_type(png_ptr, info_ptr);
479                 bit_depth = png_get_bit_depth(png_ptr, info_ptr);
480                 width  = png_get_image_width (png_ptr, info_ptr);
481                 height = png_get_image_height(png_ptr, info_ptr);
482
483                 /* Skip the alpha channel if present
484                 * stripping alpha currently doesn't work in conjunction with
485                 * converting to grayscale in libpng */
486                 pixel_width = color_type & PNG_COLOR_MASK_ALPHA ? 2 : 1;
487                 /* Convert 16 bit data to 8 bit */
488                 if( bit_depth == 16 ) png_set_strip_16(png_ptr);
489                 /* Expand to 1 pixel per byte if necessary */
490                 if( bit_depth < 8 ) png_set_packing(png_ptr);
491
492                 /* Convert to grayscale */
493                 if( color_type == PNG_COLOR_TYPE_RGB ||
494                     color_type == PNG_COLOR_TYPE_RGB_ALPHA )
495                         png_set_rgb_to_gray_fixed(png_ptr, 1, -1, -1);
496
497                 /* Allocate memory to hold the original png image */
498                 image = (png_bytep*)new png_bytep[height];
499                 for( row=0; row<(int)height; ++row )
500                         image[row] = new png_byte[width*pixel_width];
501
502                 /* Allocate memory for the pattern image that will actually be
503                 * used for the wipe */
504                 pattern_image = new  unsigned char*[frame_height];
505
506                 png_read_image(png_ptr, image);
507                 png_read_end(png_ptr, end_info);
508
509                 double row_factor, col_factor;
510                 double row_offset = 0.5, col_offset = 0.5;      // for rounding
511
512                 if( config.preserve_aspect && aspect_w && aspect_h ) {
513                         row_factor = (height-1)/aspect_h;
514                         col_factor = (width-1)/aspect_w;
515                         if( row_factor < col_factor )
516                                 col_factor = row_factor;
517                         else
518                                 row_factor = col_factor;
519                         row_factor *= aspect_h/(double)(frame_height-1);
520                         col_factor *= aspect_w/(double)(frame_width-1);
521
522                         // center the pattern over the frame
523                         row_offset += (height-1-(frame_height-1)*row_factor)/2;
524                         col_offset += (width-1-(frame_width-1)*col_factor)/2;
525                 }
526                 else {
527                         // Stretch (or shrink) the pattern image to fill the frame
528                         row_factor = (double)(height-1)/(double)(frame_height-1);
529                         col_factor = (double)(width-1)/(double)(frame_width-1);
530                 }
531                 // first, determine range min..max
532                 for( int y=0; y<frame_height; ++y ) {
533                         row = (int)(row_factor*y + row_offset);
534                         for( int x=0; x<frame_width; ++x ) {
535                                 col = (int)(col_factor*x + col_offset)*pixel_width;
536                                 value = image[row][col];
537                                 if( value < min_value ) min_value = value;
538                                 if( value > max_value ) max_value = value;
539                         }
540                 }
541                 int range = max_value - min_value;
542                 if( !range ) range = 1;
543                 // scale to fade normalized pattern_image
544                 for( int y=0; y<frame_height; ++y ) {
545                         row = (int)(row_factor*y + row_offset);
546                         pattern_image[y] = new unsigned char[frame_width];
547                         for( int x=0; x<frame_width; ++x ) {
548                                 col = (int)(col_factor*x + col_offset)*pixel_width;
549                                 value = image[row][col];
550                                 pattern_image[y][x] = 0xff*(value - min_value) / range;
551                         }
552                 }
553         }
554
555         if( png_ptr || info_ptr || end_info )
556                 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
557         if( fp )
558                 fclose(fp);
559         if( image ) {
560                 for( row=0; row<(int)height; ++row )
561                         delete [] image[row];
562                 delete [] image;
563         }
564         return ret;
565 }
566
567 void ShapeWipeMain::reset_pattern_image()
568 {
569         if( pattern_image ) {
570                 for( int y=0; y<frame_height; ++y )
571                         delete [] pattern_image[y];
572                 delete [] pattern_image;  pattern_image = 0;
573                 min_value = 255;
574                 max_value = 0;  // updated in read_pattern_image
575         }
576 }
577
578 #define SHAPEBLEND(type, components, tmp_type) { \
579         float scale = feather ? 1/feather : 0xff; \
580         type  **in_rows = (type**)input->get_rows(); \
581         type **out_rows = (type**)output->get_rows(); \
582         for( int y=y1; y<y2; ++y ) { \
583                 type *in_row = (type*) in_rows[y]; \
584                 type *out_row = (type*)out_rows[y]; \
585                 unsigned char *pattern_row = pattern_image[y]; \
586                 for( int x=0; x<w; ++x ) { \
587                         tmp_type d = (pattern_row[x] - threshold) * scale; \
588                         if( d > 0xff ) d = 0xff; \
589                         else if( d < -0xff ) d = -0xff; \
590                         tmp_type a = (d + 0xff) / 2, b = 0xff - a; \
591                         for( int i=0; i<components; ++i ) { \
592                                 type ic = in_row[i], oc = out_row[i]; \
593                                 out_row[i] = (ic * a + oc * b) / 0xff; \
594                         } \
595                         in_row += components; out_row += components; \
596                 } \
597         } \
598 }
599
600 int ShapeWipeMain::process_realtime(VFrame *input, VFrame *output)
601 {
602         this->input = input;
603         this->output = output;
604         int w = input->get_w();
605         int h = input->get_h();
606         init_shapes();
607         load_configuration();
608
609         if( strncmp(config.shape_name, current_name, BCTEXTLEN) ||
610             config.preserve_aspect != last_preserve_aspect ) {
611                 reset_pattern_image();
612         }
613         if ( !pattern_image ) {
614                 if( read_pattern_image(config.shape_name, w, h) ) {
615                         fprintf(stderr, _("Shape Wipe: cannot load shape %s\n"),
616                                 current_filename);
617                         current_filename[0] = 0;
618                         return 0;
619                 }
620                 strncpy(current_name, config.shape_name, BCTEXTLEN);
621                 last_preserve_aspect = config.preserve_aspect;
622         }
623
624         float fade = (float)PluginClient::get_source_position() /
625                 (float)PluginClient::get_total_len();
626         if( !config.direction ) fade = 1 - fade;
627         threshold = fade * 0xff;
628
629         int slices = w*h/0x40000+1;
630         int max_slices = BC_Resources::machine_cpus/2;
631         if( slices > max_slices ) slices = max_slices;
632         if( slices < 1 ) slices = 1;
633         if( engine && engine->get_total_clients() != slices ) {
634                 delete engine;  engine = 0;
635         }
636         if( !engine )
637                 engine = new ShapeEngine(this, slices, slices);
638
639         engine->process_packages();
640         return 0;
641 }
642
643
644 ShapePackage::ShapePackage()
645  : LoadPackage()
646 {
647 }
648
649 ShapeUnit::ShapeUnit(ShapeEngine *server) : LoadClient(server)
650 {
651         this->server = server;
652 }
653
654 ShapeUnit::~ShapeUnit()
655 {
656 }
657
658 void ShapeUnit::process_package(LoadPackage *package)
659 {
660         VFrame *input = server->plugin->input;
661         VFrame *output = server->plugin->output;
662         int w = input->get_w();
663
664         unsigned char **pattern_image = server->plugin->pattern_image;
665         unsigned char threshold = server->plugin->threshold;
666         float feather = server->plugin->config.feather;
667         ShapePackage *pkg = (ShapePackage*)package;
668         int y1 = pkg->y1, y2 = pkg->y2;
669
670         switch(input->get_color_model()) {
671         case BC_RGB_FLOAT:
672                 SHAPEBLEND(float, 3, float)
673                 break;
674         case BC_RGB888:
675         case BC_YUV888:
676                 SHAPEBLEND(unsigned char, 3, int)
677                 break;
678         case BC_RGBA_FLOAT:
679                 SHAPEBLEND(float, 4, float)
680                 break;
681         case BC_RGBA8888:
682         case BC_YUVA8888:
683                 SHAPEBLEND(unsigned char, 4, int)
684                 break;
685         case BC_RGB161616:
686         case BC_YUV161616:
687                 SHAPEBLEND(uint16_t, 3, int64_t)
688                 break;
689         case BC_RGBA16161616:
690         case BC_YUVA16161616:
691                 SHAPEBLEND(uint16_t, 4, int64_t)
692                 break;
693         }
694 }
695
696
697 ShapeEngine::ShapeEngine(ShapeWipeMain *plugin,
698         int total_clients, int total_packages)
699  : LoadServer(total_clients, total_packages)
700 {
701         this->plugin = plugin;
702 }
703
704 ShapeEngine::~ShapeEngine()
705 {
706 }
707
708
709 void ShapeEngine::init_packages()
710 {
711         int y = 0, h1 = plugin->input->get_h()-1;
712         int total_packages = get_total_packages();
713         for(int i = 0; i<total_packages; ) {
714                 ShapePackage *pkg = (ShapePackage*)get_package(i++);
715                 pkg->y1 = y;
716                 y = h1 * i / total_packages;
717                 pkg->y2 = y;
718         }
719 }
720
721 LoadClient* ShapeEngine::new_client()
722 {
723         return new ShapeUnit(this);
724 }
725
726 LoadPackage* ShapeEngine::new_package()
727 {
728         return new ShapePackage;
729 }
730