X-Git-Url: https://git.cinelerra-gg.org/git/?p=goodguy%2Fcinelerra.git;a=blobdiff_plain;f=cinelerra-5.1%2Fcinelerra%2Fmaskauto.C;h=47fb3f4291a97e1845b90e3f2a5092b4d9e61e4b;hp=831b899db7fead6ef8f87d4d460522dee3716cc1;hb=83b70dd60863377cb281e6be5206304e10373e30;hpb=2f0ce0b5fd34f79fc1eba949f197cea3c47d5a41 diff --git a/cinelerra-5.1/cinelerra/maskauto.C b/cinelerra-5.1/cinelerra/maskauto.C index 831b899d..47fb3f42 100644 --- a/cinelerra-5.1/cinelerra/maskauto.C +++ b/cinelerra-5.1/cinelerra/maskauto.C @@ -69,6 +69,8 @@ SubMask::SubMask(MaskAuto *keyframe, int no) this->keyframe = keyframe; memset(name, 0, sizeof(name)); sprintf(name, "%d", no); + this->fader = 100; + this->feather = 0; } SubMask::~SubMask() @@ -78,27 +80,30 @@ SubMask::~SubMask() int SubMask::equivalent(SubMask& ptr) { - if(points.size() != ptr.points.size()) return 0; - - for(int i = 0; i < points.size(); i++) - { + if( fader != ptr.fader ) return 0; + if( feather != ptr.feather ) return 0; + int n = points.size(); + if( n != ptr.points.size() ) return 0; + for( int i=0; iread_tag(); - - if(!result) - { - if(file->tag.title_is("/MASK")) - { - result = 1; - } - else - if(file->tag.title_is("POINT")) - { - XMLBuffer data; - file->read_text_until("/POINT", &data); - - MaskPoint *point = new MaskPoint; - char *ptr = data.cstr(); -//printf("MaskAuto::load 1 %s\n", ptr); - - point->x = atof(ptr); - ptr = strchr(ptr, ','); -//printf("MaskAuto::load 2 %s\n", ptr + 1); - if(ptr) - { - point->y = atof(ptr + 1); - ptr = strchr(ptr + 1, ','); - - if(ptr) - { -//printf("MaskAuto::load 3 %s\n", ptr + 1); - point->control_x1 = atof(ptr + 1); - ptr = strchr(ptr + 1, ','); - if(ptr) - { -//printf("MaskAuto::load 4 %s\n", ptr + 1); - point->control_y1 = atof(ptr + 1); - ptr = strchr(ptr + 1, ','); - if(ptr) - { -//printf("MaskAuto::load 5 %s\n", ptr + 1); - point->control_x2 = atof(ptr + 1); - ptr = strchr(ptr + 1, ','); - if(ptr) point->control_y2 = atof(ptr + 1); - } - } - } - - } - points.append(point); - } + while( !(result = file->read_tag()) ) { + if( file->tag.title_is("/MASK") ) break; + if( file->tag.title_is("POINT") ) { + XMLBuffer data; + file->read_text_until("/POINT", &data); + MaskPoint *point = new MaskPoint; + char *cp = data.cstr(); + if( cp ) point->x = strtof(cp, &cp); + if( cp && *cp==',' ) point->y = strtof(cp+1, &cp); + if( cp && *cp==',' ) point->control_x1 = strtof(cp+1, &cp); + if( cp && *cp==',' ) point->control_y1 = strtof(cp+1, &cp); + if( cp && *cp==',' ) point->control_x2 = strtof(cp+1, &cp); + if( cp && *cp==',' ) point->control_y2 = strtof(cp+1, &cp); + points.append(point); } } } @@ -174,8 +142,11 @@ void SubMask::copy(FileXML *file) if(points.total) { file->tag.set_title("MASK"); - file->tag.set_property("NUMBER", keyframe->masks.number_of(this)); + file->tag.set_property("NUMBER", + !keyframe ? -1 : keyframe->masks.number_of(this)); file->tag.set_property("NAME", name); + file->tag.set_property("FADER", fader); + file->tag.set_property("FEATHER", feather); file->append_tag(); file->append_newline(); @@ -206,18 +177,15 @@ void SubMask::copy(FileXML *file) } } -void SubMask::dump() +void SubMask::dump(FILE *fp) { - for(int i = 0; i < points.total; i++) - { - printf(" point=%d x=%.2f y=%.2f in_x=%.2f in_y=%.2f out_x=%.2f out_y=%.2f\n", - i, - points.values[i]->x, - points.values[i]->y, - points.values[i]->control_x1, - points.values[i]->control_y1, - points.values[i]->control_x2, - points.values[i]->control_y2); + for( int i=0; ix, points.values[i]->y, + points.values[i]->control_x1, points.values[i]->control_y1, + points.values[i]->control_x2, points.values[i]->control_y2); } } @@ -225,9 +193,6 @@ void SubMask::dump() MaskAuto::MaskAuto(EDL *edl, MaskAutos *autos) : Auto(edl, autos) { - mode = MASK_SUBTRACT_ALPHA; - feather = 0; - value = 100; apply_before_plugins = 0; disable_opengl_masking = 0; @@ -258,34 +223,25 @@ int MaskAuto::operator==(MaskAuto &that) int MaskAuto::identical(MaskAuto *src) { - if(value != src->value || - mode != src->mode || - feather != src->feather || - masks.size() != src->masks.size() || - apply_before_plugins != src->apply_before_plugins || - disable_opengl_masking != src->disable_opengl_masking) return 0; + if( masks.size() != src->masks.size() || + apply_before_plugins != src->apply_before_plugins || + disable_opengl_masking != src->disable_opengl_masking ) return 0; - for(int i = 0; i < masks.size(); i++) + for( int i=0; imasks.values[i])) return 0; - + } return 1; } void MaskAuto::update_parameter(MaskAuto *ref, MaskAuto *src) { - if(src->value != ref->value) - this->value = src->value; - if(src->mode != ref->mode) - this->mode = src->mode; - if(src->apply_before_plugins != ref->apply_before_plugins) + if( src->apply_before_plugins != ref->apply_before_plugins ) this->apply_before_plugins = src->apply_before_plugins; - if(src->disable_opengl_masking != ref->disable_opengl_masking) + if( src->disable_opengl_masking != ref->disable_opengl_masking ) this->disable_opengl_masking = src->disable_opengl_masking; - if(!EQUIV(src->feather, ref->feather)) - this->feather = src->feather; for( int i=0; iget_submask(i)->equivalent(*ref->get_submask(i))) + if( !src->get_submask(i)->equivalent(*ref->get_submask(i)) ) this->get_submask(i)->copy_from(*src->get_submask(i)); } } @@ -303,9 +259,6 @@ void MaskAuto::copy_from(MaskAuto *src) void MaskAuto::copy_data(MaskAuto *src) { - mode = src->mode; - feather = src->feather; - value = src->value; apply_before_plugins = src->apply_before_plugins; disable_opengl_masking = src->disable_opengl_masking; @@ -328,34 +281,28 @@ int MaskAuto::interpolate_from(Auto *a1, Auto *a2, int64_t position, Auto *templ { return Auto::interpolate_from(a1, a2, position, templ); } - this->mode = mask_auto1->mode; - this->feather = mask_auto1->feather; - this->value = mask_auto1->value; this->apply_before_plugins = mask_auto1->apply_before_plugins; this->disable_opengl_masking = mask_auto1->disable_opengl_masking; this->position = position; masks.remove_all_objects(); - for(int i = 0; - i < mask_auto1->masks.total; - i++) - { + for( int i=0; imasks.total; ++i ) { SubMask *new_submask = new SubMask(this, i); masks.append(new_submask); SubMask *mask1 = mask_auto1->masks.values[i]; SubMask *mask2 = mask_auto2->masks.values[i]; + double len = mask_auto2->position - mask_auto1->position; + double weight = !len ? 0 : (position - mask_auto1->position) / len; + new_submask->fader = mask1->fader*(1-weight) + mask2->fader*weight + 0.5; + new_submask->feather = mask1->feather*(1-weight) + mask2->feather*weight + 0.5; // just in case, should never happen int total_points = MIN(mask1->points.total, mask2->points.total); - for(int j = 0; j < total_points; j++) - { + for( int j=0; jpoints.values[j], - mask2->points.values[j], - position, - mask_auto1->position, - mask_auto2->position); + mask1->points.values[j], mask2->points.values[j], + position, mask_auto1->position, mask_auto2->position); new_submask->points.append(point); } } @@ -371,7 +318,7 @@ SubMask* MaskAuto::get_submask(int number) return masks.values[number]; } -void MaskAuto::get_points(ArrayList *points, +void MaskAuto::get_points(MaskPoints *points, int submask) { points->remove_all_objects(); @@ -384,7 +331,7 @@ void MaskAuto::get_points(ArrayList *points, } } -void MaskAuto::set_points(ArrayList *points, +void MaskAuto::set_points(MaskPoints *points, int submask) { SubMask *submask_ptr = get_submask(submask); @@ -400,13 +347,13 @@ void MaskAuto::set_points(ArrayList *points, void MaskAuto::load(FileXML *file) { - mode = file->tag.get_property("MODE", mode); - feather = file->tag.get_property("FEATHER", feather); - value = file->tag.get_property("VALUE", value); +// legacy, moved to SubMask + int old_mode = file->tag.get_property("MODE", -1); + int old_value = file->tag.get_property("VALUE", 100); + float old_feather = file->tag.get_property("FEATHER", 0); apply_before_plugins = file->tag.get_property("APPLY_BEFORE_PLUGINS", apply_before_plugins); disable_opengl_masking = file->tag.get_property("DISABLE_OPENGL_MASKING", disable_opengl_masking); - for(int i = 0; i < masks.size(); i++) - { + for( int i=0; iname, 0, sizeof(mask->name)); strncpy(mask->name, name, sizeof(mask->name)); + mask->feather = file->tag.get_property("FEATHER", old_feather); + mask->fader = file->tag.get_property("FADER", old_value); + if( old_mode == MASK_MULTIPLY_ALPHA ) + mask->fader = -mask->fader; mask->load(file); } } -// dump(); } void MaskAuto::copy(int64_t start, int64_t end, FileXML *file, int default_auto) { file->tag.set_title("AUTO"); - file->tag.set_property("MODE", mode); - file->tag.set_property("VALUE", value); - file->tag.set_property("FEATHER", feather); file->tag.set_property("APPLY_BEFORE_PLUGINS", apply_before_plugins); file->tag.set_property("DISABLE_OPENGL_MASKING", disable_opengl_masking); - - if(default_auto) - file->tag.set_property("POSITION", 0); - else - file->tag.set_property("POSITION", position - start); + file->tag.set_property("POSITION", default_auto ? 0 : position - start); file->append_tag(); file->append_newline(); - for(int i = 0; i < masks.size(); i++) - { -//printf("MaskAuto::copy 1 %p %d %p\n", this, i, masks.values[i]); + for( int i=0; icopy(file); -//printf("MaskAuto::copy 10\n"); - } file->tag.set_title("/AUTO"); file->append_tag(); file->append_newline(); } -void MaskAuto::dump() +void MaskAuto::dump(FILE *fp) { - printf(" mode=%d value=%d\n", mode, value); - for(int i = 0; i < masks.size(); i++) - { - printf(" submask %d\n", i); - masks.values[i]->dump(); + fprintf(fp,"mask_auto: apply_before_plugins %d, disable_opengl_masking %d\n", + apply_before_plugins, disable_opengl_masking); + for( int i=0; idump(fp); } } void MaskAuto::translate_submasks(float translate_x, float translate_y) { - for(int i = 0; i < masks.size(); i++) - { + for( int i=0; ipoints.total; j++) - { + for( int j=0; jpoints.total; ++j ) { mask->points.values[j]->x += translate_x; mask->points.values[j]->y += translate_y; } @@ -481,11 +418,9 @@ void MaskAuto::translate_submasks(float translate_x, float translate_y) void MaskAuto::scale_submasks(int orig_scale, int new_scale) { - for(int i = 0; i < masks.size(); i++) - { + for( int i=0; ipoints.total; j++) - { + for( int j=0; jpoints.total; ++j ) { float orig_x = mask->points.values[j]->x * orig_scale; float orig_y = mask->points.values[j]->y * orig_scale; mask->points.values[j]->x = orig_x / new_scale; @@ -504,4 +439,97 @@ void MaskAuto::scale_submasks(int orig_scale, int new_scale) } } +int MaskAuto::has_active_mask() +{ + int total_points = 0; + float min_fader = 100; + for( int i=0; ipoints.size(); + if( submask_points > 1 ) total_points += submask_points; + int fader = mask->fader; + if( fader < min_fader ) min_fader = fader; + } + return min_fader >= 0 && total_points < 2 ? 0 : 1; +} + +static inline double line_dist(float cx,float cy, float tx,float ty) +{ + double dx = tx-cx, dy = ty-cy; + return sqrt(dx*dx + dy*dy); +} + +void MaskEdge::load(MaskPoints &points, float ofs) +{ + remove_all(); + int first_point = 1; +// Need to tabulate every vertex in persistent memory because +// gluTessVertex doesn't copy them. + for( int i=0; i= points.total-1) ? + points.values[0] : points.values[i+1]; + + int segments = 0; + if( !point1->control_x2 && !point1->control_y2 && + !point2->control_x1 && !point2->control_y1 ) + segments = 1; + + float x0 = point1->x, y0 = point1->y; + float x1 = point1->x + point1->control_x2; + float y1 = point1->y + point1->control_y2; + float x2 = point2->x + point2->control_x1; + float y2 = point2->y + point2->control_y1; + float x3 = point2->x, y3 = point2->y; + + // forward differencing bezier curves implementation taken from GPL code at + // http://cvs.sourceforge.net/viewcvs.py/guliverkli/guliverkli/src/subtitles/Rasterizer.cpp?rev=1.3 + + float cx3, cx2, cx1, cx0; + float cy3, cy2, cy1, cy0; + + // [-1 +3 -3 +1] + // [+3 -6 +3 0] + // [-3 +3 0 0] + // [+1 0 0 0] + + cx3 = - x0 + 3*x1 - 3*x2 + x3; + cx2 = 3*x0 - 6*x1 + 3*x2; + cx1 = -3*x0 + 3*x1; + cx0 = x0; + + cy3 = - y0 + 3*y1 - 3*y2 + y3; + cy2 = 3*y0 - 6*y1 + 3*y2; + cy1 = -3*y0 + 3*y1; + cy0 = y0; + + // This equation is from Graphics Gems I. + // + // The idea is that since we're approximating a cubic curve with lines, + // any error we incur is due to the curvature of the line, which we can + // estimate by calculating the maximum acceleration of the curve. For + // a cubic, the acceleration (second derivative) is a line, meaning that + // the absolute maximum acceleration must occur at either the beginning + // (|c2|) or the end (|c2+c3|). Our bounds here are a little more + // conservative than that, but that's okay. + if( !segments ) { + float maxaccel1 = fabs(2*cy2) + fabs(6*cy3); + float maxaccel2 = fabs(2*cx2) + fabs(6*cx3); + float maxaccel = maxaccel1 > maxaccel2 ? maxaccel1 : maxaccel2; + segments = maxaccel > 1.0 ? sqrt(maxaccel) : + 1 + line_dist(point1->x,point1->y, point2->x,point2->y); + } + + for( int j=0; j<=segments; ++j ) { + float t = (float)j / segments; + float x = cx0 + t*(cx1 + t*(cx2 + t*cx3)); + float y = cy0 + t*(cy1 + t*(cy2 + t*cy3)); + + if( j > 0 || first_point ) { + append(x, y-ofs); + first_point = 0; + } + } + } +}