4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
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.
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.
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
25 #include "maskautos.h"
31 MaskPoint::MaskPoint()
41 void MaskPoint::copy_from(MaskPoint &ptr)
45 this->control_x1 = ptr.control_x1;
46 this->control_y1 = ptr.control_y1;
47 this->control_x2 = ptr.control_x2;
48 this->control_y2 = ptr.control_y2;
51 MaskPoint& MaskPoint::operator=(MaskPoint& ptr)
57 int MaskPoint::operator==(MaskPoint& ptr)
59 return EQUIV(x, ptr.x) &&
61 EQUIV(control_x1, ptr.control_x1) &&
62 EQUIV(control_y1, ptr.control_y1) &&
63 EQUIV(control_x2, ptr.control_x2) &&
64 EQUIV(control_y2, ptr.control_y2);
67 SubMask::SubMask(MaskAuto *keyframe)
69 this->keyframe = keyframe;
76 int SubMask::equivalent(SubMask& ptr)
78 if(points.size() != ptr.points.size()) return 0;
80 for(int i = 0; i < points.size(); i++)
82 if(!(*points.get(i) == *ptr.points.get(i)))
90 int SubMask::operator==(SubMask& ptr)
92 return equivalent(ptr);
95 void SubMask::copy_from(SubMask& ptr)
97 points.remove_all_objects();
98 //printf("SubMask::copy_from 1 %p %d\n", this, ptr.points.total);
99 for(int i = 0; i < ptr.points.total; i++)
101 MaskPoint *point = new MaskPoint;
102 *point = *ptr.points.values[i];
103 points.append(point);
107 void SubMask::load(FileXML *file)
109 points.remove_all_objects();
114 result = file->read_tag();
118 if(file->tag.title_is("/MASK"))
123 if(file->tag.title_is("POINT"))
125 char string[BCTEXTLEN];
127 file->read_text_until("/POINT", string, BCTEXTLEN);
129 MaskPoint *point = new MaskPoint;
131 //printf("MaskAuto::load 1 %s\n", ptr);
133 point->x = atof(ptr);
134 ptr = strchr(ptr, ',');
135 //printf("MaskAuto::load 2 %s\n", ptr + 1);
138 point->y = atof(ptr + 1);
139 ptr = strchr(ptr + 1, ',');
143 //printf("MaskAuto::load 3 %s\n", ptr + 1);
144 point->control_x1 = atof(ptr + 1);
145 ptr = strchr(ptr + 1, ',');
148 //printf("MaskAuto::load 4 %s\n", ptr + 1);
149 point->control_y1 = atof(ptr + 1);
150 ptr = strchr(ptr + 1, ',');
153 //printf("MaskAuto::load 5 %s\n", ptr + 1);
154 point->control_x2 = atof(ptr + 1);
155 ptr = strchr(ptr + 1, ',');
156 if(ptr) point->control_y2 = atof(ptr + 1);
162 points.append(point);
168 void SubMask::copy(FileXML *file)
172 file->tag.set_title("MASK");
173 file->tag.set_property("NUMBER", keyframe->masks.number_of(this));
175 file->append_newline();
177 for(int i = 0; i < points.total; i++)
179 file->append_newline();
180 file->tag.set_title("POINT");
182 char string[BCTEXTLEN];
183 //printf("SubMask::copy 1 %p %d %p\n", this, i, points.values[i]);
184 sprintf(string, "%.7g, %.7g, %.7g, %.7g, %.7g, %.7g",
187 points.values[i]->control_x1,
188 points.values[i]->control_y1,
189 points.values[i]->control_x2,
190 points.values[i]->control_y2);
191 //printf("SubMask::copy 2\n");
192 file->append_text(string);
193 file->tag.set_title("/POINT");
196 file->append_newline();
198 file->tag.set_title("/MASK");
200 file->append_newline();
206 for(int i = 0; i < points.total; i++)
208 printf(" point=%d x=%.2f y=%.2f in_x=%.2f in_y=%.2f out_x=%.2f out_y=%.2f\n",
212 points.values[i]->control_x1,
213 points.values[i]->control_y1,
214 points.values[i]->control_x2,
215 points.values[i]->control_y2);
220 MaskAuto::MaskAuto(EDL *edl, MaskAutos *autos)
223 mode = MASK_SUBTRACT_ALPHA;
226 apply_before_plugins = 0;
228 // We define a fixed number of submasks so that interpolation for each
231 for(int i = 0; i < SUBMASKS; i++)
232 masks.append(new SubMask(this));
235 MaskAuto::~MaskAuto()
237 masks.remove_all_objects();
240 int MaskAuto::operator==(Auto &that)
242 return identical((MaskAuto*)&that);
247 int MaskAuto::operator==(MaskAuto &that)
249 return identical((MaskAuto*)&that);
253 int MaskAuto::identical(MaskAuto *src)
255 if(value != src->value ||
257 feather != src->feather ||
258 masks.size() != src->masks.size() ||
259 apply_before_plugins != src->apply_before_plugins) return 0;
261 for(int i = 0; i < masks.size(); i++)
262 if(!(*masks.values[i] == *src->masks.values[i])) return 0;
267 void MaskAuto::update_parameter(MaskAuto *ref, MaskAuto *src)
269 if(src->value != ref->value)
271 this->value = src->value;
274 if(src->mode != ref->mode)
276 this->mode = src->mode;
279 if(!EQUIV(src->feather, ref->feather))
281 this->feather = src->feather;
284 for(int i = 0; i < masks.size(); i++)
286 if(!src->get_submask(i)->equivalent(*ref->get_submask(i)))
287 this->get_submask(i)->copy_from(*src->get_submask(i));
291 void MaskAuto::copy_from(Auto *src)
293 copy_from((MaskAuto*)src);
296 void MaskAuto::copy_from(MaskAuto *src)
298 Auto::copy_from(src);
302 void MaskAuto::copy_data(MaskAuto *src)
305 feather = src->feather;
307 apply_before_plugins = src->apply_before_plugins;
309 masks.remove_all_objects();
310 for(int i = 0; i < src->masks.size(); i++)
312 masks.append(new SubMask(this));
313 masks.values[i]->copy_from(*src->masks.values[i]);
317 int MaskAuto::interpolate_from(Auto *a1, Auto *a2, int64_t position, Auto *templ) {
318 if(!a1) a1 = previous;
320 MaskAuto *mask_auto1 = (MaskAuto *)a1;
321 MaskAuto *mask_auto2 = (MaskAuto *)a2;
323 if (!mask_auto2 || !mask_auto1 || mask_auto2->masks.total == 0)
324 // can't interpolate, fall back to copying (using template if possible)
326 return Auto::interpolate_from(a1, a2, position, templ);
328 this->mode = mask_auto1->mode;
329 this->feather = mask_auto1->feather;
330 this->value = mask_auto1->value;
331 this->apply_before_plugins = mask_auto1->apply_before_plugins;
332 this->position = position;
333 masks.remove_all_objects();
336 i < mask_auto1->masks.total;
339 SubMask *new_submask = new SubMask(this);
340 masks.append(new_submask);
341 SubMask *mask1 = mask_auto1->masks.values[i];
342 SubMask *mask2 = mask_auto2->masks.values[i];
344 // just in case, should never happen
345 int total_points = MIN(mask1->points.total, mask2->points.total);
346 for(int j = 0; j < total_points; j++)
348 MaskPoint *point = new MaskPoint;
349 MaskAutos::avg_points(point,
350 mask1->points.values[j],
351 mask2->points.values[j],
353 mask_auto1->position,
354 mask_auto2->position);
355 new_submask->points.append(point);
364 SubMask* MaskAuto::get_submask(int number)
366 CLAMP(number, 0, masks.size() - 1);
367 return masks.values[number];
370 void MaskAuto::get_points(ArrayList<MaskPoint*> *points,
373 points->remove_all_objects();
374 SubMask *submask_ptr = get_submask(submask);
375 for(int i = 0; i < submask_ptr->points.size(); i++)
377 MaskPoint *point = new MaskPoint;
378 point->copy_from(*submask_ptr->points.get(i));
379 points->append(point);
383 void MaskAuto::set_points(ArrayList<MaskPoint*> *points,
386 SubMask *submask_ptr = get_submask(submask);
387 submask_ptr->points.remove_all_objects();
388 for(int i = 0; i < points->size(); i++)
390 MaskPoint *point = new MaskPoint;
391 point->copy_from(*points->get(i));
392 submask_ptr->points.append(point);
397 void MaskAuto::load(FileXML *file)
399 mode = file->tag.get_property("MODE", mode);
400 feather = file->tag.get_property("FEATHER", feather);
401 value = file->tag.get_property("VALUE", value);
402 apply_before_plugins = file->tag.get_property("APPLY_BEFORE_PLUGINS", apply_before_plugins);
403 for(int i = 0; i < masks.size(); i++)
405 delete masks.values[i];
406 masks.values[i] = new SubMask(this);
412 result = file->read_tag();
416 if(file->tag.title_is("/AUTO"))
419 if(file->tag.title_is("MASK"))
421 SubMask *mask = masks.values[file->tag.get_property("NUMBER", 0)];
429 void MaskAuto::copy(int64_t start, int64_t end, FileXML *file, int default_auto)
431 file->tag.set_title("AUTO");
432 file->tag.set_property("MODE", mode);
433 file->tag.set_property("VALUE", value);
434 file->tag.set_property("FEATHER", feather);
435 file->tag.set_property("APPLY_BEFORE_PLUGINS", apply_before_plugins);
438 file->tag.set_property("POSITION", 0);
440 file->tag.set_property("POSITION", position - start);
442 file->append_newline();
444 for(int i = 0; i < masks.size(); i++)
446 //printf("MaskAuto::copy 1 %p %d %p\n", this, i, masks.values[i]);
447 masks.values[i]->copy(file);
448 //printf("MaskAuto::copy 10\n");
451 file->append_newline();
452 file->tag.set_title("/AUTO");
454 file->append_newline();
457 void MaskAuto::dump()
459 printf(" mode=%d value=%d\n", mode, value);
460 for(int i = 0; i < masks.size(); i++)
462 printf(" submask %d\n", i);
463 masks.values[i]->dump();
467 void MaskAuto::translate_submasks(float translate_x, float translate_y)
469 for(int i = 0; i < masks.size(); i++)
471 SubMask *mask = get_submask(i);
472 for (int j = 0; j < mask->points.total; j++)
474 mask->points.values[j]->x += translate_x;
475 mask->points.values[j]->y += translate_y;
480 void MaskAuto::scale_submasks(int orig_scale, int new_scale)
482 for(int i = 0; i < masks.size(); i++)
484 SubMask *mask = get_submask(i);
485 for (int j = 0; j < mask->points.total; j++)
487 float orig_x = mask->points.values[j]->x * orig_scale;
488 float orig_y = mask->points.values[j]->y * orig_scale;
489 mask->points.values[j]->x = orig_x / new_scale;
490 mask->points.values[j]->y = orig_y / new_scale;
492 orig_x = mask->points.values[j]->control_x1 * orig_scale;
493 orig_y = mask->points.values[j]->control_y1 * orig_scale;
494 mask->points.values[j]->control_x1 = orig_x / new_scale;
495 mask->points.values[j]->control_y1 = orig_y / new_scale;
497 orig_x = mask->points.values[j]->control_x2 * orig_scale;
498 orig_y = mask->points.values[j]->control_y2 * orig_scale;
499 mask->points.values[j]->control_x2 = orig_x / new_scale;
500 mask->points.values[j]->control_y2 = orig_y / new_scale;