X-Git-Url: https://git.cinelerra-gg.org/git/?p=goodguy%2Fcinelerra.git;a=blobdiff_plain;f=cinelerra-5.1%2Fplugins%2Fshapewipe%2Fshapewipe.C;h=a360fd5ee1e1be275bd7fb81c79a9d087aefb665;hp=9a38a916b03de086ae3f4cfa33c3779d26a13f33;hb=befe1fe45b4ac2b6430d43c6e6f6d8ecad9795e0;hpb=6ca0a7892ec6459a54fcb3ba3a223d1ddc5ce402 diff --git a/cinelerra-5.1/plugins/shapewipe/shapewipe.C b/cinelerra-5.1/plugins/shapewipe/shapewipe.C index 9a38a916..a360fd5e 100644 --- a/cinelerra-5.1/plugins/shapewipe/shapewipe.C +++ b/cinelerra-5.1/plugins/shapewipe/shapewipe.C @@ -38,17 +38,56 @@ #define SHAPE_SEARCHPATH "/shapes" #define DEFAULT_SHAPE "circle" +// feather slider range log2 = -10 .. -1 == 9.8e-4 .. 0.5 +#define SHAPE_FLOG_MIN -10. +#define SHAPE_FLOG_MAX -1. REGISTER_PLUGIN(ShapeWipeMain) +ShapeWipeConfig::ShapeWipeConfig() +{ + direction = 0; + feather = 0; + preserve_aspect = 0; + strcpy(shape_name, DEFAULT_SHAPE); +} +ShapeWipeConfig::~ShapeWipeConfig() +{ +} + +void ShapeWipeConfig::read_xml(KeyFrame *keyframe) +{ + FileXML input; + input.set_shared_input(keyframe->xbuf); + + while( !input.read_tag() ) { + if( input.tag.title_is("SHAPEWIPE") ) { + direction = input.tag.get_property("DIRECTION", direction); + feather = input.tag.get_property("FEATHER", feather); + preserve_aspect = input.tag.get_property("PRESERVE_ASPECT", preserve_aspect); + input.tag.get_property("SHAPE_NAME", shape_name); + } + } +} +void ShapeWipeConfig::save_xml(KeyFrame *keyframe) +{ + FileXML output; + output.set_shared_output(keyframe->xbuf); + output.tag.set_title("SHAPEWIPE"); + output.tag.set_property("DIRECTION", direction); + output.tag.set_property("FEATHER", feather); + output.tag.set_property("PRESERVE_ASPECT", preserve_aspect); + output.tag.set_property("SHAPE_NAME", shape_name); + output.append_tag(); + output.tag.set_title("/SHAPEWIPE"); + output.append_tag(); + output.terminate_string(); +} + + ShapeWipeW2B::ShapeWipeW2B(ShapeWipeMain *plugin, - ShapeWipeWindow *window, - int x, - int y) - : BC_Radial(x, - y, - plugin->direction == 0, - _("White to Black")) + ShapeWipeWindow *window, int x, int y) + : BC_Radial(x, y, plugin->config.direction == 0, _("White to Black")) { this->plugin = plugin; this->window = window; @@ -57,20 +96,15 @@ ShapeWipeW2B::ShapeWipeW2B(ShapeWipeMain *plugin, int ShapeWipeW2B::handle_event() { update(1); - plugin->direction = 0; + plugin->config.direction = 0; window->right->update(0); plugin->send_configure_change(); return 0; } ShapeWipeB2W::ShapeWipeB2W(ShapeWipeMain *plugin, - ShapeWipeWindow *window, - int x, - int y) - : BC_Radial(x, - y, - plugin->direction == 1, - _("Black to White")) + ShapeWipeWindow *window, int x, int y) + : BC_Radial(x, y, plugin->config.direction == 1, _("Black to White")) { this->plugin = plugin; this->window = window; @@ -79,34 +113,16 @@ ShapeWipeB2W::ShapeWipeB2W(ShapeWipeMain *plugin, int ShapeWipeB2W::handle_event() { update(1); - plugin->direction = 1; + plugin->config.direction = 1; window->left->update(0); plugin->send_configure_change(); return 0; } -ShapeWipeAntiAlias::ShapeWipeAntiAlias(ShapeWipeMain *plugin, - ShapeWipeWindow *window, - int x, - int y) - : BC_CheckBox (x,y,plugin->antialias, _("Anti-aliasing")) -{ - this->plugin = plugin; - this->window = window; -} - -int ShapeWipeAntiAlias::handle_event() -{ - plugin->antialias = get_value(); - plugin->send_configure_change(); - return 0; -} ShapeWipePreserveAspectRatio::ShapeWipePreserveAspectRatio(ShapeWipeMain *plugin, - ShapeWipeWindow *window, - int x, - int y) - : BC_CheckBox (x, y, plugin->preserve_aspect, _("Preserve shape aspect ratio")) + ShapeWipeWindow *window, int x, int y) + : BC_CheckBox (x, y, plugin->config.preserve_aspect, _("Preserve shape aspect ratio")) { this->plugin = plugin; this->window = window; @@ -114,24 +130,19 @@ ShapeWipePreserveAspectRatio::ShapeWipePreserveAspectRatio(ShapeWipeMain *plugin int ShapeWipePreserveAspectRatio::handle_event() { - plugin->preserve_aspect = get_value(); + plugin->config.preserve_aspect = get_value(); plugin->send_configure_change(); return 0; } - - - - ShapeWipeTumble::ShapeWipeTumble(ShapeWipeMain *client, - ShapeWipeWindow *window, - int x, - int y) + ShapeWipeWindow *window, int x, int y) : BC_Tumbler(x, y) { this->client = client; this->window = window; + set_increment(0.01); } int ShapeWipeTumble::handle_up_event() @@ -147,24 +158,40 @@ int ShapeWipeTumble::handle_down_event() } +ShapeWipeFeather::ShapeWipeFeather(ShapeWipeMain *client, + ShapeWipeWindow *window, int x, int y) + : BC_FSlider(x, y, 0, 150, 150, SHAPE_FLOG_MIN, SHAPE_FLOG_MAX, + !client->config.feather ? SHAPE_FLOG_MIN : + log(client->config.feather)/M_LN2) +{ + this->client = client; + this->window = window; + set_precision(0.001); + set_pagination(0.01, 0.1); +} +char *ShapeWipeFeather::get_caption() +{ + double v = get_value(); + char *caption = BC_Slider::get_caption(); + sprintf(caption, "%-5.3f", exp(v*M_LN2)); + return caption; +} - +int ShapeWipeFeather::handle_event() +{ + float v = get_value(); + client->config.feather = exp(M_LN2*v); + client->send_configure_change(); + return 1; +} ShapeWipeShape::ShapeWipeShape(ShapeWipeMain *client, - ShapeWipeWindow *window, - int x, - int y, - int text_w, - int list_h) - : BC_PopupTextBox(window, - &window->shapes, - client->shape_name, - x, - y, - text_w, - list_h) + ShapeWipeWindow *window, int x, int y, + int text_w, int list_h) + : BC_PopupTextBox(window, &window->shapes, client->config.shape_name, + x, y, text_w, list_h) { this->client = client; this->window = window; @@ -172,25 +199,14 @@ ShapeWipeShape::ShapeWipeShape(ShapeWipeMain *client, int ShapeWipeShape::handle_event() { - strcpy(client->shape_name, get_text()); + strcpy(client->config.shape_name, get_text()); client->send_configure_change(); return 1; } - - - - - - ShapeWipeWindow::ShapeWipeWindow(ShapeWipeMain *plugin) - : PluginClientWindow(plugin, - 450, - 125, - 450, - 125, - 0) + : PluginClientWindow(plugin, 450, 125, 450, 125, 0) { this->plugin = plugin; } @@ -201,7 +217,6 @@ ShapeWipeWindow::~ShapeWipeWindow() } - void ShapeWipeWindow::create_objects() { BC_Title *title = 0; @@ -211,22 +226,17 @@ void ShapeWipeWindow::create_objects() int x = window_border, y = window_border; plugin->init_shapes(); - for(int i = 0; i < plugin->shape_titles.size(); i++) - { + for( int i=0; ishape_titles.size(); ++i ) { shapes.append(new BC_ListBoxItem(plugin->shape_titles.get(i))); } add_subwindow(title = new BC_Title(x, y, _("Direction:"))); x += title->get_w() + widget_border; add_subwindow(left = new ShapeWipeW2B(plugin, - this, - x, - y)); + this, x, y)); x += left->get_w() + widget_border; add_subwindow(right = new ShapeWipeB2W(plugin, - this, - x, - y)); + this, x, y)); x = window_border; y += right->get_h() + widget_border; @@ -234,48 +244,24 @@ void ShapeWipeWindow::create_objects() add_subwindow(title = new BC_Title(x, y, _("Shape:"))); x += title->get_w() + widget_border; -// add_subwindow(filename_widget = new -// ShapeWipeFilename(plugin, -// this, -// plugin->filename, -// x, -// y)); -// x += 200; -// add_subwindow(new ShapeWipeBrowseButton( -// plugin, -// this, -// filename_widget, -// x, -// y)); - shape_text = new ShapeWipeShape(plugin, - this, - x, - y, - 150, - 200); + this, x, y, 150, 200); shape_text->create_objects(); x += shape_text->get_w() + widget_border; add_subwindow(new ShapeWipeTumble(plugin, - this, - x, - y)); - x = window_border; + this, x, y)); y += shape_text->get_h() + widget_border; - ShapeWipeAntiAlias *anti_alias; - add_subwindow(anti_alias = new ShapeWipeAntiAlias( - plugin, - this, - x, - y)); - y += anti_alias->get_h() + widget_border; + x = window_border; + add_subwindow(title = new BC_Title(x, y, _("Feather:"))); + x += title->get_w() + widget_border; + add_subwindow(shape_feather = new ShapeWipeFeather(plugin, this, x, y)); + y += shape_feather->get_h() + widget_border; + + x = window_border; ShapeWipePreserveAspectRatio *aspect_ratio; add_subwindow(aspect_ratio = new ShapeWipePreserveAspectRatio( - plugin, - this, - x, - y)); + plugin, this, x, y)); y += aspect_ratio->get_h() + widget_border; show_window(); @@ -284,53 +270,44 @@ void ShapeWipeWindow::create_objects() void ShapeWipeWindow::next_shape() { - for(int i = 0; i < plugin->shape_titles.size(); i++) - { - if(!strcmp(plugin->shape_titles.get(i), plugin->shape_name)) - { - i++; - if(i >= plugin->shape_titles.size()) i = 0; - strcpy(plugin->shape_name, plugin->shape_titles.get(i)); - shape_text->update(plugin->shape_name); - break; - } + ShapeWipeConfig &config = plugin->config; + int k = plugin->shape_titles.size(); + while( --k>=0 && strcmp(plugin->shape_titles.get(k),config.shape_name) ); + + if( k >= 0 ) { + if( ++k >= plugin->shape_titles.size() ) k = 0; + strcpy(config.shape_name, plugin->shape_titles.get(k)); + shape_text->update(config.shape_name); } client->send_configure_change(); } void ShapeWipeWindow::prev_shape() { - for(int i = 0; i < plugin->shape_titles.size(); i++) - { - if(!strcmp(plugin->shape_titles.get(i), plugin->shape_name)) - { - i--; - if(i < 0) i = plugin->shape_titles.size() - 1; - strcpy(plugin->shape_name, plugin->shape_titles.get(i)); - shape_text->update(plugin->shape_name); - break; - } + ShapeWipeConfig &config = plugin->config; + int k = plugin->shape_titles.size(); + while( --k>=0 && strcmp(plugin->shape_titles.get(k),config.shape_name) ); + + if( k >= 0 ) { + if( --k < 0 ) k = plugin->shape_titles.size()-1; + strcpy(config.shape_name, plugin->shape_titles.get(k)); + shape_text->update(config.shape_name); } client->send_configure_change(); } - - - ShapeWipeMain::ShapeWipeMain(PluginServer *server) : PluginVClient(server) { - direction = 0; - filename[0] = 0; - last_read_filename[0] = '\0'; - strcpy(shape_name, DEFAULT_SHAPE); + input = 0; + output = 0; + engine = 0; + current_filename[0] = '\0'; current_name[0] = 0; - pattern_image = NULL; - min_value = (unsigned char)255; - max_value = (unsigned char)0; - antialias = 0; - preserve_aspect = 0; + pattern_image = 0; + min_value = 255; + max_value = 0; last_preserve_aspect = 0; shapes_initialized = 0; shape_paths.set_array_delete(); @@ -342,6 +319,7 @@ ShapeWipeMain::~ShapeWipeMain() reset_pattern_image(); shape_paths.remove_all_objects(); shape_titles.remove_all_objects(); + delete engine; } const char* ShapeWipeMain::plugin_title() { return N_("Shape Wipe"); } @@ -350,58 +328,27 @@ int ShapeWipeMain::uses_gui() { return 1; } NEW_WINDOW_MACRO(ShapeWipeMain, ShapeWipeWindow); - - -void ShapeWipeMain::save_data(KeyFrame *keyframe) +void ShapeWipeMain::read_data(KeyFrame *keyframe) { - FileXML output; - output.set_shared_output(keyframe->xbuf); - output.tag.set_title("SHAPEWIPE"); - output.tag.set_property("DIRECTION", direction); - output.tag.set_property("ANTIALIAS", antialias); - output.tag.set_property("PRESERVE_ASPECT", preserve_aspect); - output.tag.set_property("FILENAME", filename); - output.tag.set_property("SHAPE_NAME", shape_name); - output.append_tag(); - output.tag.set_title("/SHAPEWIPE"); - output.append_tag(); - output.terminate_string(); + config.read_xml(keyframe); } - -void ShapeWipeMain::read_data(KeyFrame *keyframe) +void ShapeWipeMain::save_data(KeyFrame *keyframe) { - FileXML input; - - input.set_shared_input(keyframe->xbuf); - - while(!input.read_tag()) - { - if(input.tag.title_is("SHAPEWIPE")) - { - direction = input.tag.get_property("DIRECTION", direction); - antialias = input.tag.get_property("ANTIALIAS", antialias); - preserve_aspect = input.tag.get_property("PRESERVE_ASPECT", preserve_aspect); - input.tag.get_property("FILENAME", filename); - input.tag.get_property("SHAPE_NAME", shape_name); - } - } + config.save_xml(keyframe); } void ShapeWipeMain::init_shapes() { - if(!shapes_initialized) - { + if( !shapes_initialized ) { FileSystem fs; fs.set_filter("*.png"); char shape_path[BCTEXTLEN]; sprintf(shape_path, "%s%s", get_plugin_dir(), SHAPE_SEARCHPATH); fs.update(shape_path); - for(int i = 0; i < fs.total_files(); i++) - { + for( int i=0; iget_is_dir()) - { + if( !file_item->get_is_dir() ) { shape_paths.append(cstrdup(file_item->get_path())); char *ptr = cstrdup(file_item->get_name()); char *ptr2 = strrchr(ptr, '.'); @@ -421,643 +368,309 @@ int ShapeWipeMain::load_configuration() return 1; } -int ShapeWipeMain::read_pattern_image(int new_frame_width, int new_frame_height) +int ShapeWipeMain::read_pattern_image(char *shape_name, + int new_frame_width, int new_frame_height) { png_byte header[8]; int is_png; - int row; - int col; - int scaled_row; - int scaled_col; + int row, col; int pixel_width; unsigned char value; png_uint_32 width; png_uint_32 height; png_byte color_type; png_byte bit_depth; - png_structp png_ptr; - png_infop info_ptr; - png_infop end_info; - png_bytep *image; + png_structp png_ptr = 0; + png_infop info_ptr = 0; + png_infop end_info = 0; + png_bytep *image = 0; + FILE *fp = 0; frame_width = new_frame_width; frame_height = new_frame_height; + int ret = 0; // Convert name to filename - for(int i = 0; i < shape_paths.size(); i++) - { - if(!strcmp(shape_titles.get(i), shape_name)) - { - strcpy(filename, shape_paths.get(i)); - break; - } + int k = shape_paths.size(); + while( --k>=0 && strcmp(shape_titles[k], shape_name) ); + if( k < 0 ) ret = 1; + if( !ret ) { + strcpy(current_filename, shape_paths[k]); + fp = fopen(current_filename, "rb"); + if( !fp ) ret = 1; } - - FILE *fp = fopen(filename, "rb"); - if (!fp) - { - return 1; + if( !ret ) { + fread(header, 1, 8, fp); + is_png = !png_sig_cmp(header, 0, 8); + if( !is_png ) ret = 1; } - - fread(header, 1, 8, fp); - is_png = !png_sig_cmp(header, 0, 8); - - if (!is_png) - { - fclose(fp); - return 1; - } - - png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, - NULL, NULL, NULL); - - if (!png_ptr) - { - fclose(fp); - return 1; + if( !ret ) { + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); + if( !png_ptr ) ret = 1; } - - /* Tell libpng we already checked the first 8 bytes */ - png_set_sig_bytes(png_ptr, 8); - - info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) - { - png_destroy_read_struct(&png_ptr, NULL, NULL); - fclose(fp); - return 1; - } - - end_info = png_create_info_struct(png_ptr); - if (!end_info) - { - png_destroy_read_struct(&png_ptr, &info_ptr, NULL); - fclose(fp); - return 1; - } - - png_init_io(png_ptr, fp); - png_read_info(png_ptr, info_ptr); - - color_type = png_get_color_type(png_ptr, info_ptr); - bit_depth = png_get_bit_depth(png_ptr, info_ptr); - width = png_get_image_width (png_ptr, info_ptr); - height = png_get_image_height(png_ptr, info_ptr); - - /* Skip the alpha channel if present - * stripping alpha currently doesn't work in conjunction with - * converting to grayscale in libpng */ - if (color_type & PNG_COLOR_MASK_ALPHA) - pixel_width = 2; - else - pixel_width = 1; - - /* Convert 16 bit data to 8 bit */ - if (bit_depth == 16) png_set_strip_16(png_ptr); - - /* Expand to 1 pixel per byte if necessary */ - if (bit_depth < 8) png_set_packing(png_ptr); - - /* Convert to grayscale */ - if (color_type == PNG_COLOR_TYPE_RGB || - color_type == PNG_COLOR_TYPE_RGB_ALPHA) - png_set_rgb_to_gray_fixed(png_ptr, 1, -1, -1); - - /* Allocate memory to hold the original png image */ - image = (png_bytep*)malloc(sizeof(png_bytep)*height); - for (row = 0; row < (int)height; row++) - { - image[row] = (png_byte*)malloc(sizeof(png_byte)*width*pixel_width); - } - - /* Allocate memory for the pattern image that will actually be - * used for the wipe */ - pattern_image = (unsigned char**)malloc(sizeof(unsigned char*)*frame_height); - - - png_read_image(png_ptr, image); - png_read_end(png_ptr, end_info); - - double row_factor, col_factor; - double row_offset = 0.5, col_offset = 0.5; // for rounding - - if (preserve_aspect && aspect_w != 0 && aspect_h != 0) - { - row_factor = (height-1)/aspect_h; - col_factor = (width-1)/aspect_w; - if (row_factor < col_factor) - col_factor = row_factor; - else - row_factor = col_factor; - row_factor *= aspect_h/(double)(frame_height-1); - col_factor *= aspect_w/(double)(frame_width-1); - - // center the pattern over the frame - row_offset += (height-1-(frame_height-1)*row_factor)/2; - col_offset += (width-1-(frame_width-1)*col_factor)/2; + if( !ret ) { + /* Tell libpng we already checked the first 8 bytes */ + png_set_sig_bytes(png_ptr, 8); + info_ptr = png_create_info_struct(png_ptr); + if( !info_ptr ) ret = 1; } - else - { - // Stretch (or shrink) the pattern image to fill the frame - row_factor = (double)(height-1)/(double)(frame_height-1); - col_factor = (double)(width-1)/(double)(frame_width-1); + if( !ret ) { + end_info = png_create_info_struct(png_ptr); + if( !end_info ) ret = 1; } - - for (scaled_row = 0; scaled_row < frame_height; scaled_row++) - { - row = (int)(row_factor*scaled_row + row_offset); - pattern_image[scaled_row] = (unsigned char*)malloc(sizeof(unsigned char)*frame_width); - for (scaled_col = 0; scaled_col < frame_width; scaled_col++) - { - col = (int)(col_factor*scaled_col + col_offset)*pixel_width; - value = image[row][col]; - pattern_image[scaled_row][scaled_col] = value; - if (value < min_value) min_value = value; - if (value > max_value) max_value = value; - + if( !ret ) { + png_init_io(png_ptr, fp); + png_read_info(png_ptr, info_ptr); + + color_type = png_get_color_type(png_ptr, info_ptr); + bit_depth = png_get_bit_depth(png_ptr, info_ptr); + width = png_get_image_width (png_ptr, info_ptr); + height = png_get_image_height(png_ptr, info_ptr); + + /* Skip the alpha channel if present + * stripping alpha currently doesn't work in conjunction with + * converting to grayscale in libpng */ + pixel_width = color_type & PNG_COLOR_MASK_ALPHA ? 2 : 1; + /* Convert 16 bit data to 8 bit */ + if( bit_depth == 16 ) png_set_strip_16(png_ptr); + /* Expand to 1 pixel per byte if necessary */ + if( bit_depth < 8 ) png_set_packing(png_ptr); + + /* Convert to grayscale */ + if( color_type == PNG_COLOR_TYPE_RGB || + color_type == PNG_COLOR_TYPE_RGB_ALPHA ) + png_set_rgb_to_gray_fixed(png_ptr, 1, -1, -1); + + /* Allocate memory to hold the original png image */ + image = (png_bytep*)new png_bytep[height]; + for( row=0; row<(int)height; ++row ) + image[row] = new png_byte[width*pixel_width]; + + /* Allocate memory for the pattern image that will actually be + * used for the wipe */ + pattern_image = new unsigned char*[frame_height]; + + png_read_image(png_ptr, image); + png_read_end(png_ptr, end_info); + + double row_factor, col_factor; + double row_offset = 0.5, col_offset = 0.5; // for rounding + + if( config.preserve_aspect && aspect_w && aspect_h ) { + row_factor = (height-1)/aspect_h; + col_factor = (width-1)/aspect_w; + if( row_factor < col_factor ) + col_factor = row_factor; + else + row_factor = col_factor; + row_factor *= aspect_h/(double)(frame_height-1); + col_factor *= aspect_w/(double)(frame_width-1); + + // center the pattern over the frame + row_offset += (height-1-(frame_height-1)*row_factor)/2; + col_offset += (width-1-(frame_width-1)*col_factor)/2; + } + else { + // Stretch (or shrink) the pattern image to fill the frame + row_factor = (double)(height-1)/(double)(frame_height-1); + col_factor = (double)(width-1)/(double)(frame_width-1); + } + // first, determine range min..max + for( int y=0; y max_value ) max_value = value; + } + } + int range = max_value - min_value; + if( !range ) range = 1; + // scale to fade normalized pattern_image + for( int y=0; yget_rows(); \ - type **out_rows = (type**)outgoing->get_rows(); \ - \ - type *in_row; \ - type *out_row; \ - \ - if( !direction ) { \ - for(j = 0; j < h; j++) { \ - in_row = (type*) in_rows[j]; \ - out_row = (type*)out_rows[j]; \ - pattern_row = pattern_image[j]; \ - \ - col_offset = 0; \ - for(k = 0; k < w; k++, col_offset += components ) { \ - value = pattern_row[k]; \ - if (value < threshold) continue; \ - out_row[col_offset] = in_row[col_offset]; \ - out_row[col_offset + 1] = in_row[col_offset + 1]; \ - out_row[col_offset + 2] = in_row[col_offset + 2]; \ - if(components == 4) \ - out_row[col_offset + 3] = in_row[col_offset + 3]; \ +#define SHAPEBLEND(type, components, tmp_type) { \ + float scale = feather ? 1/feather : 0xff; \ + type **in_rows = (type**)input->get_rows(); \ + type **out_rows = (type**)output->get_rows(); \ + for( int y=y1; y 0xff ) d = 0xff; \ + else if( d < -0xff ) d = -0xff; \ + tmp_type a = (d + 0xff) / 2, b = 0xff - a; \ + for( int i=0; i threshold) continue; \ - out_row[col_offset] = in_row[col_offset]; \ - out_row[col_offset + 1] = in_row[col_offset + 1]; \ - out_row[col_offset + 2] = in_row[col_offset + 2]; \ - if(components == 4) \ - out_row[col_offset + 3] = in_row[col_offset + 3]; \ - } \ - } \ - } \ -} - -#define COMPARE1(x,y) \ -{ \ - if (pattern_image[x][y] <= threshold) opacity++; \ -} - -#define COMPARE2(x,y) \ -{ \ - if (pattern_image[x][y] >= threshold) opacity++; \ -} - -// components is always 4 -#define BLEND_ONLY_4_NORMAL(temp_type, type, max, chroma_offset,x,y) \ -{ \ - const int bits = sizeof(type) * 8; \ - temp_type blend_opacity = (temp_type)(alpha * ((temp_type)1 << bits) + 0.5); \ - temp_type blend_transparency = ((temp_type)1 << bits) - blend_opacity; \ - \ - col = y * 4; \ - type* in_row = (type*)incoming->get_rows()[x]; \ - type* output = (type*)outgoing->get_rows()[x]; \ - \ - output[col] = ((temp_type)in_row[col] * blend_opacity + output[col] * blend_transparency) >> bits; \ - output[col+1] = ((temp_type)in_row[col+1] * blend_opacity + output[col+1] * blend_transparency) >> bits; \ - output[col+2] = ((temp_type)in_row[col+2] * blend_opacity + output[col+2] * blend_transparency) >> bits; \ -} - - -// components is always 3 -#define BLEND_ONLY_3_NORMAL(temp_type, type, max, chroma_offset,x,y) \ -{ \ - const int bits = sizeof(type) * 8; \ - temp_type blend_opacity = (temp_type)(alpha * ((temp_type)1 << bits) + 0.5); \ - temp_type blend_transparency = ((temp_type)1 << bits) - blend_opacity; \ - \ - col = y * 3; \ - type* in_row = (type*)incoming->get_rows()[x]; \ - type* output = (type*)outgoing->get_rows()[x]; \ - \ - output[col] = ((temp_type)in_row[col] * blend_opacity + output[col] * blend_transparency) >> bits; \ - output[col+1] = ((temp_type)in_row[col+1] * blend_opacity + output[col+1] * blend_transparency) >> bits; \ - output[col+2] = ((temp_type)in_row[col+2] * blend_opacity + output[col+2] * blend_transparency) >> bits; \ } -/* opacity is defined as opacity of incoming frame */ -#define BLEND(x,y,total) \ -{ \ - float pixel_opacity = (float)opacity / total; \ - float alpha = pixel_opacity; \ - float pixel_transparency = 1.0 - pixel_opacity; \ - int col; \ - \ - if (pixel_opacity > 0.0) \ - { \ - switch(incoming->get_color_model()) \ - { \ - case BC_RGB_FLOAT: \ - { \ - float *in_row = (float*)incoming->get_rows()[x]; \ - float *out_row = (float*)outgoing->get_rows()[x]; \ - col = y * 3; \ - out_row[col] = in_row[col] * pixel_opacity + \ - out_row[col] * pixel_transparency; \ - out_row[col+1] = in_row[col+1] * pixel_opacity + \ - out_row[col+1] * pixel_transparency; \ - out_row[col+2] = in_row[col+2] * pixel_opacity + \ - out_row[col+2] * pixel_transparency; \ - break; \ - } \ - case BC_RGBA_FLOAT: \ - { \ - float *in_row = (float*)incoming->get_rows()[x]; \ - float *out_row = (float*)outgoing->get_rows()[x]; \ - col = y * 4; \ - out_row[col] = in_row[col] * pixel_opacity + \ - out_row[col] * pixel_transparency; \ - out_row[col+1] = in_row[col+1] * pixel_opacity + \ - out_row[col+1] * pixel_transparency; \ - out_row[col+2] = in_row[col+2] * pixel_opacity + \ - out_row[col+2] * pixel_transparency; \ - break; \ - } \ - case BC_RGB888: \ - BLEND_ONLY_3_NORMAL(uint32_t, unsigned char, 0xff, 0,x,y); \ - break; \ - case BC_YUV888: \ - BLEND_ONLY_3_NORMAL(int32_t, unsigned char, 0xff, 0x80,x,y); \ - break; \ - case BC_RGBA8888: \ - BLEND_ONLY_4_NORMAL(uint32_t, unsigned char, 0xff, 0,x,y); \ - break; \ - case BC_YUVA8888: \ - BLEND_ONLY_4_NORMAL(int32_t, unsigned char, 0xff, 0x80,x,y); \ - break; \ - case BC_RGB161616: \ - BLEND_ONLY_3_NORMAL(uint64_t, uint16_t, 0xffff, 0,x,y); \ - break; \ - case BC_YUV161616: \ - BLEND_ONLY_3_NORMAL(int64_t, uint16_t, 0xffff, 0x8000,x,y); \ - break; \ - case BC_RGBA16161616: \ - BLEND_ONLY_4_NORMAL(uint64_t, uint16_t, 0xffff, 0,x,y); \ - break; \ - case BC_YUVA16161616: \ - BLEND_ONLY_4_NORMAL(int64_t, uint16_t, 0xffff, 0x8000,x,y); \ - break; \ - } \ - } \ -} - -int ShapeWipeMain::process_realtime(VFrame *incoming, VFrame *outgoing) +int ShapeWipeMain::process_realtime(VFrame *input, VFrame *output) { - unsigned char *pattern_row; - int col_offset; - unsigned char threshold; - unsigned char value; - int j, k; - int opacity; - + this->input = input; + this->output = output; + int w = input->get_w(); + int h = input->get_h(); init_shapes(); load_configuration(); - int w = incoming->get_w(); - int h = incoming->get_h(); - - if (strncmp(filename, last_read_filename, BCTEXTLEN) || - strncmp(shape_name, current_name, BCTEXTLEN) || - preserve_aspect != last_preserve_aspect) - { + if( strncmp(config.shape_name, current_name, BCTEXTLEN) || + config.preserve_aspect != last_preserve_aspect ) { reset_pattern_image(); } - - if (!pattern_image) - { - read_pattern_image(w, h); - strncpy(last_read_filename, filename, BCTEXTLEN); - last_preserve_aspect = preserve_aspect; - - if (pattern_image) - { - strncpy(last_read_filename, filename, BCTEXTLEN); - strncpy(current_name, shape_name, BCTEXTLEN); - last_preserve_aspect = preserve_aspect; - } - else { - fprintf(stderr, _("Shape Wipe: cannot load shape %s\n"), filename); - last_read_filename[0] = 0; + if ( !pattern_image ) { + if( read_pattern_image(config.shape_name, w, h) ) { + fprintf(stderr, _("Shape Wipe: cannot load shape %s\n"), + current_filename); + current_filename[0] = 0; return 0; } + strncpy(current_name, config.shape_name, BCTEXTLEN); + last_preserve_aspect = config.preserve_aspect; } - if (direction) - { - threshold = (unsigned char)( - (float)PluginClient::get_source_position() / - (float)PluginClient::get_total_len() * - (float)(max_value - min_value)) - + min_value; - } - else - { - threshold = (unsigned char)((max_value - min_value) - ( - (float)PluginClient::get_source_position() / - (float)PluginClient::get_total_len() * - (float)(max_value - min_value))) - + min_value; + float fade = (float)PluginClient::get_source_position() / + (float)PluginClient::get_total_len(); + if( !config.direction ) fade = 1 - fade; + threshold = fade * 0xff; + + int slices = w*h/0x40000+1; + int max_slices = BC_Resources::machine_cpus/2; + if( slices > max_slices ) slices = max_slices; + if( slices < 1 ) slices = 1; + if( engine && engine->get_total_clients() != slices ) { + delete engine; engine = 0; } + if( !engine ) + engine = new ShapeEngine(this, slices, slices); - if (antialias) - { - if (direction) - { - /* Top left corner */ - opacity = 0; - COMPARE1(0,0); - COMPARE1(0,1); - COMPARE1(1,0); - COMPARE1(1,1); - BLEND(0,0,4.0); - - /* Top edge */ - for (k = 1; k < w-1; k++) - { - opacity = 0; - COMPARE1(0,k-1); - COMPARE1(0,k); - COMPARE1(0,k+1); - COMPARE1(1,k-1); - COMPARE1(1,k); - COMPARE1(1,k+1); - BLEND(0,k,6.0); - } + engine->process_packages(); + return 0; +} - /* Top right corner */ - opacity = 0; - COMPARE1(0,w-1); - COMPARE1(0,w-2); - COMPARE1(1,w-1); - COMPARE1(1,w-2); - BLEND(0,w-1,4.0); - - /* Left edge */ - for (j = 1; j < h-1; j++) - { - opacity = 0; - COMPARE1(j-1,0); - COMPARE1(j,0); - COMPARE1(j+1,0); - COMPARE1(j-1,1); - COMPARE1(j,1); - COMPARE1(j+1,1); - BLEND(j,0,6.0); - } - /* Middle */ - for (j = 1; j < h-1; j++) - { - for (k = 1; k < w-1; k++) - { - opacity = 0; - COMPARE1(j-1,k-1); - COMPARE1(j,k-1); - COMPARE1(j+1,k-1); - COMPARE1(j-1,k); - COMPARE1(j,k); - COMPARE1(j+1,k); - COMPARE1(j-1,k+1); - COMPARE1(j,k+1); - COMPARE1(j+1,k+1); - BLEND(j,k,9.0); - } - } +ShapePackage::ShapePackage() + : LoadPackage() +{ +} - /* Right edge */ - for (j = 1; j < h-1; j++) - { - opacity = 0; - COMPARE1(j-1,w-1); - COMPARE1(j,w-1); - COMPARE1(j+1,w-1); - COMPARE1(j-1,w-2); - COMPARE1(j,w-2); - COMPARE1(j+1,w-2); - BLEND(j,w-1,6.0); - } +ShapeUnit::ShapeUnit(ShapeEngine *server) : LoadClient(server) +{ + this->server = server; +} - /* Bottom left corner */ - opacity = 0; - COMPARE1(h-1,0); - COMPARE1(h-1,1); - COMPARE1(h-2,0); - COMPARE1(h-2,1); - BLEND(h-1,0,4.0); - - /* Bottom edge */ - for (k = 1; k < w-1; k++) - { - opacity = 0; - COMPARE1(h-1,k-1); - COMPARE1(h-1,k); - COMPARE1(h-1,k+1); - COMPARE1(h-2,k-1); - COMPARE1(h-2,k); - COMPARE1(h-2,k+1); - BLEND(h-1,k,6.0); - } +ShapeUnit::~ShapeUnit() +{ +} - /* Bottom right corner */ - opacity = 0; - COMPARE1(h-1,w-1); - COMPARE1(h-1,w-2); - COMPARE1(h-2,w-1); - COMPARE1(h-2,w-2); - BLEND(h-1,w-1,4.0); - } - else - { - /* Top left corner */ - opacity = 0; - COMPARE2(0,0); - COMPARE2(0,1); - COMPARE2(1,0); - COMPARE2(1,1); - BLEND(0,0,4.0); - - /* Top edge */ - for (k = 1; k < w-1; k++) - { - opacity = 0; - COMPARE2(0,k-1); - COMPARE2(0,k); - COMPARE2(0,k+1); - COMPARE2(1,k-1); - COMPARE2(1,k); - COMPARE2(1,k+1); - BLEND(0,k,6.0); - } +void ShapeUnit::process_package(LoadPackage *package) +{ + VFrame *input = server->plugin->input; + VFrame *output = server->plugin->output; + int w = input->get_w(); + + unsigned char **pattern_image = server->plugin->pattern_image; + unsigned char threshold = server->plugin->threshold; + float feather = server->plugin->config.feather; + ShapePackage *pkg = (ShapePackage*)package; + int y1 = pkg->y1, y2 = pkg->y2; + + switch(input->get_color_model()) { + case BC_RGB_FLOAT: + SHAPEBLEND(float, 3, float) + break; + case BC_RGB888: + case BC_YUV888: + SHAPEBLEND(unsigned char, 3, int) + break; + case BC_RGBA_FLOAT: + SHAPEBLEND(float, 4, float) + break; + case BC_RGBA8888: + case BC_YUVA8888: + SHAPEBLEND(unsigned char, 4, int) + break; + case BC_RGB161616: + case BC_YUV161616: + SHAPEBLEND(uint16_t, 3, int64_t) + break; + case BC_RGBA16161616: + case BC_YUVA16161616: + SHAPEBLEND(uint16_t, 4, int64_t) + break; + } +} - /* Top right corner */ - opacity = 0; - COMPARE2(0,w-1); - COMPARE2(0,w-2); - COMPARE2(1,w-1); - COMPARE2(1,w-2); - BLEND(0,w-1,4.0); - - /* Left edge */ - for (j = 1; j < h-1; j++) - { - opacity = 0; - COMPARE2(j-1,0); - COMPARE2(j,0); - COMPARE2(j+1,0); - COMPARE2(j-1,1); - COMPARE2(j,1); - COMPARE2(j+1,1); - BLEND(j,0,6.0); - } - /* Middle */ - for (j = 1; j < h-1; j++) - { - for (k = 1; k < w-1; k++) - { - opacity = 0; - COMPARE2(j-1,k-1); - COMPARE2(j,k-1); - COMPARE2(j+1,k-1); - COMPARE2(j-1,k); - COMPARE2(j,k); - COMPARE2(j+1,k); - COMPARE2(j-1,k+1); - COMPARE2(j,k+1); - COMPARE2(j+1,k+1); - BLEND(j,k,9.0); - } - } +ShapeEngine::ShapeEngine(ShapeWipeMain *plugin, + int total_clients, int total_packages) + : LoadServer(total_clients, total_packages) +{ + this->plugin = plugin; +} - /* Right edge */ - for (j = 1; j < h-1; j++) - { - opacity = 0; - COMPARE2(j-1,w-1); - COMPARE2(j,w-1); - COMPARE2(j+1,w-1); - COMPARE2(j-1,w-2); - COMPARE2(j,w-2); - COMPARE2(j+1,w-2); - BLEND(j,w-1,6.0); - } +ShapeEngine::~ShapeEngine() +{ +} - /* Bottom left corner */ - opacity = 0; - COMPARE2(h-1,0); - COMPARE2(h-1,1); - COMPARE2(h-2,0); - COMPARE2(h-2,1); - BLEND(h-1,0,4.0); - - /* Bottom edge */ - for (k = 1; k < w-1; k++) - { - opacity = 0; - COMPARE2(h-1,k-1); - COMPARE2(h-1,k); - COMPARE2(h-1,k+1); - COMPARE2(h-2,k-1); - COMPARE2(h-2,k); - COMPARE2(h-2,k+1); - BLEND(h-1,k,6.0); - } - /* Bottom right corner */ - opacity = 0; - COMPARE2(h-1,w-1); - COMPARE2(h-1,w-2); - COMPARE2(h-2,w-1); - COMPARE2(h-2,w-2); - BLEND(h-1,w-1,4.0); - } - } - else - { - switch(incoming->get_color_model()) - { - case BC_RGB_FLOAT: - SHAPEWIPE(float, 3) - break; - case BC_RGB888: - case BC_YUV888: - SHAPEWIPE(unsigned char, 3) - break; - case BC_RGBA_FLOAT: - SHAPEWIPE(float, 4) - break; - case BC_RGBA8888: - case BC_YUVA8888: - SHAPEWIPE(unsigned char, 4) - break; - case BC_RGB161616: - case BC_YUV161616: - SHAPEWIPE(uint16_t, 3) - break; - case BC_RGBA16161616: - case BC_YUVA16161616: - SHAPEWIPE(uint16_t, 4) - break; - } +void ShapeEngine::init_packages() +{ + int y = 0, h1 = plugin->input->get_h()-1; + int total_packages = get_total_packages(); + for(int i = 0; iy1 = y; + y = h1 * i / total_packages; + pkg->y2 = y; } - return 0; } + +LoadClient* ShapeEngine::new_client() +{ + return new ShapeUnit(this); +} + +LoadPackage* ShapeEngine::new_package() +{ + return new ShapePackage; +} +