X-Git-Url: http://git.cinelerra-gg.org/git/?a=blobdiff_plain;f=cinelerra-5.1%2Fcinelerra%2Fmaskauto.C;fp=cinelerra-5.1%2Fcinelerra%2Fmaskauto.C;h=d5beae3bee2315915e50ab4813704bf145075eb3;hb=30bdb85eb33a8ee7ba675038a86c6be59c43d7bd;hp=0000000000000000000000000000000000000000;hpb=52fcc46226f9df46f9ce9d0566dc568455a7db0b;p=goodguy%2Fhistory.git diff --git a/cinelerra-5.1/cinelerra/maskauto.C b/cinelerra-5.1/cinelerra/maskauto.C new file mode 100644 index 00000000..d5beae3b --- /dev/null +++ b/cinelerra-5.1/cinelerra/maskauto.C @@ -0,0 +1,505 @@ + +/* + * CINELERRA + * Copyright (C) 2008 Adam Williams + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "clip.h" +#include "filexml.h" +#include "maskauto.h" +#include "maskautos.h" + +#include +#include + + +MaskPoint::MaskPoint() +{ + x = 0; + y = 0; + control_x1 = 0; + control_y1 = 0; + control_x2 = 0; + control_y2 = 0; +} + +void MaskPoint::copy_from(MaskPoint &ptr) +{ + this->x = ptr.x; + this->y = ptr.y; + this->control_x1 = ptr.control_x1; + this->control_y1 = ptr.control_y1; + this->control_x2 = ptr.control_x2; + this->control_y2 = ptr.control_y2; +} + +MaskPoint& MaskPoint::operator=(MaskPoint& ptr) +{ + copy_from(ptr); + return *this; +} + +int MaskPoint::operator==(MaskPoint& ptr) +{ + return EQUIV(x, ptr.x) && + EQUIV(y, ptr.y) && + EQUIV(control_x1, ptr.control_x1) && + EQUIV(control_y1, ptr.control_y1) && + EQUIV(control_x2, ptr.control_x2) && + EQUIV(control_y2, ptr.control_y2); +} + +SubMask::SubMask(MaskAuto *keyframe) +{ + this->keyframe = keyframe; +} + +SubMask::~SubMask() +{ +} + +int SubMask::equivalent(SubMask& ptr) +{ + if(points.size() != ptr.points.size()) return 0; + + for(int i = 0; i < points.size(); i++) + { + if(!(*points.get(i) == *ptr.points.get(i))) + return 0; + } + + return 1; +} + + +int SubMask::operator==(SubMask& ptr) +{ + return equivalent(ptr); +} + +void SubMask::copy_from(SubMask& ptr) +{ + points.remove_all_objects(); +//printf("SubMask::copy_from 1 %p %d\n", this, ptr.points.total); + for(int i = 0; i < ptr.points.total; i++) + { + MaskPoint *point = new MaskPoint; + *point = *ptr.points.values[i]; + points.append(point); + } +} + +void SubMask::load(FileXML *file) +{ + points.remove_all_objects(); + + int result = 0; + while(!result) + { + result = file->read_tag(); + + if(!result) + { + if(file->tag.title_is("/MASK")) + { + result = 1; + } + else + if(file->tag.title_is("POINT")) + { + char string[BCTEXTLEN]; + string[0] = 0; + file->read_text_until("/POINT", string, BCTEXTLEN); + + MaskPoint *point = new MaskPoint; + char *ptr = string; +//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); + } + } + } +} + +void SubMask::copy(FileXML *file) +{ + if(points.total) + { + file->tag.set_title("MASK"); + file->tag.set_property("NUMBER", keyframe->masks.number_of(this)); + file->append_tag(); + file->append_newline(); + + for(int i = 0; i < points.total; i++) + { + file->append_newline(); + file->tag.set_title("POINT"); + file->append_tag(); + char string[BCTEXTLEN]; +//printf("SubMask::copy 1 %p %d %p\n", this, i, points.values[i]); + sprintf(string, "%.7g, %.7g, %.7g, %.7g, %.7g, %.7g", + 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); +//printf("SubMask::copy 2\n"); + file->append_text(string); + file->tag.set_title("/POINT"); + file->append_tag(); + } + file->append_newline(); + + file->tag.set_title("/MASK"); + file->append_tag(); + file->append_newline(); + } +} + +void SubMask::dump() +{ + 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); + } +} + + +MaskAuto::MaskAuto(EDL *edl, MaskAutos *autos) + : Auto(edl, autos) +{ + mode = MASK_SUBTRACT_ALPHA; + feather = 0; + value = 100; + apply_before_plugins = 0; + +// We define a fixed number of submasks so that interpolation for each +// submask matches. + + for(int i = 0; i < SUBMASKS; i++) + masks.append(new SubMask(this)); +} + +MaskAuto::~MaskAuto() +{ + masks.remove_all_objects(); +} + +int MaskAuto::operator==(Auto &that) +{ + return identical((MaskAuto*)&that); +} + + + +int MaskAuto::operator==(MaskAuto &that) +{ + return identical((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) return 0; + + for(int i = 0; i < masks.size(); i++) + if(!(*masks.values[i] == *src->masks.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(!EQUIV(src->feather, ref->feather)) + { + this->feather = src->feather; + } + + for(int i = 0; i < masks.size(); i++) + { + if(!src->get_submask(i)->equivalent(*ref->get_submask(i))) + this->get_submask(i)->copy_from(*src->get_submask(i)); + } +} + +void MaskAuto::copy_from(Auto *src) +{ + copy_from((MaskAuto*)src); +} + +void MaskAuto::copy_from(MaskAuto *src) +{ + Auto::copy_from(src); + copy_data(src); +} + +void MaskAuto::copy_data(MaskAuto *src) +{ + mode = src->mode; + feather = src->feather; + value = src->value; + apply_before_plugins = src->apply_before_plugins; + + masks.remove_all_objects(); + for(int i = 0; i < src->masks.size(); i++) + { + masks.append(new SubMask(this)); + masks.values[i]->copy_from(*src->masks.values[i]); + } +} + +int MaskAuto::interpolate_from(Auto *a1, Auto *a2, int64_t position, Auto *templ) { + if(!a1) a1 = previous; + if(!a2) a2 = next; + MaskAuto *mask_auto1 = (MaskAuto *)a1; + MaskAuto *mask_auto2 = (MaskAuto *)a2; + + if (!mask_auto2 || !mask_auto1 || mask_auto2->masks.total == 0) + // can't interpolate, fall back to copying (using template if possible) + { + 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->position = position; + masks.remove_all_objects(); + + for(int i = 0; + i < mask_auto1->masks.total; + i++) + { + SubMask *new_submask = new SubMask(this); + masks.append(new_submask); + SubMask *mask1 = mask_auto1->masks.values[i]; + SubMask *mask2 = mask_auto2->masks.values[i]; + + // just in case, should never happen + int total_points = MIN(mask1->points.total, mask2->points.total); + for(int j = 0; j < total_points; j++) + { + MaskPoint *point = new MaskPoint; + MaskAutos::avg_points(point, + mask1->points.values[j], + mask2->points.values[j], + position, + mask_auto1->position, + mask_auto2->position); + new_submask->points.append(point); + } + } + return 1; + + +} + + +SubMask* MaskAuto::get_submask(int number) +{ + CLAMP(number, 0, masks.size() - 1); + return masks.values[number]; +} + +void MaskAuto::get_points(ArrayList *points, + int submask) +{ + points->remove_all_objects(); + SubMask *submask_ptr = get_submask(submask); + for(int i = 0; i < submask_ptr->points.size(); i++) + { + MaskPoint *point = new MaskPoint; + point->copy_from(*submask_ptr->points.get(i)); + points->append(point); + } +} + +void MaskAuto::set_points(ArrayList *points, + int submask) +{ + SubMask *submask_ptr = get_submask(submask); + submask_ptr->points.remove_all_objects(); + for(int i = 0; i < points->size(); i++) + { + MaskPoint *point = new MaskPoint; + point->copy_from(*points->get(i)); + submask_ptr->points.append(point); + } +} + + +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); + apply_before_plugins = file->tag.get_property("APPLY_BEFORE_PLUGINS", apply_before_plugins); + for(int i = 0; i < masks.size(); i++) + { + delete masks.values[i]; + masks.values[i] = new SubMask(this); + } + + int result = 0; + while(!result) + { + result = file->read_tag(); + + if(!result) + { + if(file->tag.title_is("/AUTO")) + result = 1; + else + if(file->tag.title_is("MASK")) + { + SubMask *mask = masks.values[file->tag.get_property("NUMBER", 0)]; + 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); + + if(default_auto) + file->tag.set_property("POSITION", 0); + else + file->tag.set_property("POSITION", 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]); + masks.values[i]->copy(file); +//printf("MaskAuto::copy 10\n"); + } + + file->append_newline(); + file->tag.set_title("/AUTO"); + file->append_tag(); + file->append_newline(); +} + +void MaskAuto::dump() +{ + 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(); + } +} + +void MaskAuto::translate_submasks(float translate_x, float translate_y) +{ + for(int i = 0; i < masks.size(); i++) + { + SubMask *mask = get_submask(i); + for (int j = 0; j < mask->points.total; j++) + { + mask->points.values[j]->x += translate_x; + mask->points.values[j]->y += translate_y; + } + } +} + +void MaskAuto::scale_submasks(int orig_scale, int new_scale) +{ + for(int i = 0; i < masks.size(); i++) + { + SubMask *mask = get_submask(i); + for (int j = 0; j < mask->points.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; + mask->points.values[j]->y = orig_y / new_scale; + + orig_x = mask->points.values[j]->control_x1 * orig_scale; + orig_y = mask->points.values[j]->control_y1 * orig_scale; + mask->points.values[j]->control_x1 = orig_x / new_scale; + mask->points.values[j]->control_y1 = orig_y / new_scale; + + orig_x = mask->points.values[j]->control_x2 * orig_scale; + orig_y = mask->points.values[j]->control_y2 * orig_scale; + mask->points.values[j]->control_x2 = orig_x / new_scale; + mask->points.values[j]->control_y2 = orig_y / new_scale; + } + } +} + +