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, int no)
69 this->keyframe = keyframe;
70 memset(name, 0, sizeof(name));
71 sprintf(name, "%d", no);
76 points.remove_all_objects();
79 int SubMask::equivalent(SubMask& ptr)
81 if(points.size() != ptr.points.size()) return 0;
83 for(int i = 0; i < points.size(); i++)
85 if(!(*points.get(i) == *ptr.points.get(i)))
93 int SubMask::operator==(SubMask& ptr)
95 return equivalent(ptr);
98 void SubMask::copy_from(SubMask& ptr)
100 memset(name, 0, sizeof(name));
101 strncpy(name, ptr.name, sizeof(name-1));
102 points.remove_all_objects();
103 //printf("SubMask::copy_from 1 %p %d\n", this, ptr.points.total);
104 for(int i = 0; i < ptr.points.total; i++)
106 MaskPoint *point = new MaskPoint;
107 *point = *ptr.points.values[i];
108 points.append(point);
112 void SubMask::load(FileXML *file)
114 points.remove_all_objects();
119 result = file->read_tag();
123 if(file->tag.title_is("/MASK"))
128 if(file->tag.title_is("POINT"))
131 file->read_text_until("/POINT", &data);
133 MaskPoint *point = new MaskPoint;
134 char *ptr = data.cstr();
135 //printf("MaskAuto::load 1 %s\n", ptr);
137 point->x = atof(ptr);
138 ptr = strchr(ptr, ',');
139 //printf("MaskAuto::load 2 %s\n", ptr + 1);
142 point->y = atof(ptr + 1);
143 ptr = strchr(ptr + 1, ',');
147 //printf("MaskAuto::load 3 %s\n", ptr + 1);
148 point->control_x1 = atof(ptr + 1);
149 ptr = strchr(ptr + 1, ',');
152 //printf("MaskAuto::load 4 %s\n", ptr + 1);
153 point->control_y1 = atof(ptr + 1);
154 ptr = strchr(ptr + 1, ',');
157 //printf("MaskAuto::load 5 %s\n", ptr + 1);
158 point->control_x2 = atof(ptr + 1);
159 ptr = strchr(ptr + 1, ',');
160 if(ptr) point->control_y2 = atof(ptr + 1);
166 points.append(point);
172 void SubMask::copy(FileXML *file)
176 file->tag.set_title("MASK");
177 file->tag.set_property("NUMBER", keyframe->masks.number_of(this));
178 file->tag.set_property("NAME", name);
180 file->append_newline();
182 for(int i = 0; i < points.total; i++)
184 file->append_newline();
185 file->tag.set_title("POINT");
187 char string[BCTEXTLEN];
188 //printf("SubMask::copy 1 %p %d %p\n", this, i, points.values[i]);
189 sprintf(string, "%.7g, %.7g, %.7g, %.7g, %.7g, %.7g",
192 points.values[i]->control_x1,
193 points.values[i]->control_y1,
194 points.values[i]->control_x2,
195 points.values[i]->control_y2);
196 //printf("SubMask::copy 2\n");
197 file->append_text(string);
198 file->tag.set_title("/POINT");
201 file->append_newline();
203 file->tag.set_title("/MASK");
205 file->append_newline();
211 for(int i = 0; i < points.total; i++)
213 printf(" point=%d x=%.2f y=%.2f in_x=%.2f in_y=%.2f out_x=%.2f out_y=%.2f\n",
217 points.values[i]->control_x1,
218 points.values[i]->control_y1,
219 points.values[i]->control_x2,
220 points.values[i]->control_y2);
225 MaskAuto::MaskAuto(EDL *edl, MaskAutos *autos)
228 mode = MASK_SUBTRACT_ALPHA;
231 apply_before_plugins = 0;
232 disable_opengl_masking = 0;
234 // We define a fixed number of submasks so that interpolation for each
237 for(int i = 0; i < SUBMASKS; i++)
238 masks.append(new SubMask(this, i));
241 MaskAuto::~MaskAuto()
243 masks.remove_all_objects();
246 int MaskAuto::operator==(Auto &that)
248 return identical((MaskAuto*)&that);
253 int MaskAuto::operator==(MaskAuto &that)
255 return identical((MaskAuto*)&that);
259 int MaskAuto::identical(MaskAuto *src)
261 if(value != src->value ||
263 feather != src->feather ||
264 masks.size() != src->masks.size() ||
265 apply_before_plugins != src->apply_before_plugins ||
266 disable_opengl_masking != src->disable_opengl_masking) return 0;
268 for(int i = 0; i < masks.size(); i++)
269 if(!(*masks.values[i] == *src->masks.values[i])) return 0;
274 void MaskAuto::update_parameter(MaskAuto *ref, MaskAuto *src)
276 if(src->value != ref->value)
277 this->value = src->value;
278 if(src->mode != ref->mode)
279 this->mode = src->mode;
280 if(src->apply_before_plugins != ref->apply_before_plugins)
281 this->apply_before_plugins = src->apply_before_plugins;
282 if(src->disable_opengl_masking != ref->disable_opengl_masking)
283 this->disable_opengl_masking = src->disable_opengl_masking;
284 if(!EQUIV(src->feather, ref->feather))
285 this->feather = src->feather;
287 for( int i=0; i<masks.size(); ++i ) {
288 if(!src->get_submask(i)->equivalent(*ref->get_submask(i)))
289 this->get_submask(i)->copy_from(*src->get_submask(i));
293 void MaskAuto::copy_from(Auto *src)
295 copy_from((MaskAuto*)src);
298 void MaskAuto::copy_from(MaskAuto *src)
300 Auto::copy_from(src);
304 void MaskAuto::copy_data(MaskAuto *src)
307 feather = src->feather;
309 apply_before_plugins = src->apply_before_plugins;
310 disable_opengl_masking = src->disable_opengl_masking;
312 masks.remove_all_objects();
313 for(int i = 0; i < src->masks.size(); i++)
315 masks.append(new SubMask(this, i));
316 masks.values[i]->copy_from(*src->masks.values[i]);
320 int MaskAuto::interpolate_from(Auto *a1, Auto *a2, int64_t position, Auto *templ) {
321 if(!a1) a1 = previous;
323 MaskAuto *mask_auto1 = (MaskAuto *)a1;
324 MaskAuto *mask_auto2 = (MaskAuto *)a2;
326 if (!mask_auto2 || !mask_auto1 || mask_auto2->masks.total == 0)
327 // can't interpolate, fall back to copying (using template if possible)
329 return Auto::interpolate_from(a1, a2, position, templ);
331 this->mode = mask_auto1->mode;
332 this->feather = mask_auto1->feather;
333 this->value = mask_auto1->value;
334 this->apply_before_plugins = mask_auto1->apply_before_plugins;
335 this->disable_opengl_masking = mask_auto1->disable_opengl_masking;
336 this->position = position;
337 masks.remove_all_objects();
340 i < mask_auto1->masks.total;
343 SubMask *new_submask = new SubMask(this, i);
344 masks.append(new_submask);
345 SubMask *mask1 = mask_auto1->masks.values[i];
346 SubMask *mask2 = mask_auto2->masks.values[i];
348 // just in case, should never happen
349 int total_points = MIN(mask1->points.total, mask2->points.total);
350 for(int j = 0; j < total_points; j++)
352 MaskPoint *point = new MaskPoint;
353 MaskAutos::avg_points(point,
354 mask1->points.values[j],
355 mask2->points.values[j],
357 mask_auto1->position,
358 mask_auto2->position);
359 new_submask->points.append(point);
368 SubMask* MaskAuto::get_submask(int number)
370 CLAMP(number, 0, masks.size() - 1);
371 return masks.values[number];
374 void MaskAuto::get_points(ArrayList<MaskPoint*> *points,
377 points->remove_all_objects();
378 SubMask *submask_ptr = get_submask(submask);
379 for(int i = 0; i < submask_ptr->points.size(); i++)
381 MaskPoint *point = new MaskPoint;
382 point->copy_from(*submask_ptr->points.get(i));
383 points->append(point);
387 void MaskAuto::set_points(ArrayList<MaskPoint*> *points,
390 SubMask *submask_ptr = get_submask(submask);
391 submask_ptr->points.remove_all_objects();
392 for(int i = 0; i < points->size(); i++)
394 MaskPoint *point = new MaskPoint;
395 point->copy_from(*points->get(i));
396 submask_ptr->points.append(point);
401 void MaskAuto::load(FileXML *file)
403 mode = file->tag.get_property("MODE", mode);
404 feather = file->tag.get_property("FEATHER", feather);
405 value = file->tag.get_property("VALUE", value);
406 apply_before_plugins = file->tag.get_property("APPLY_BEFORE_PLUGINS", apply_before_plugins);
407 disable_opengl_masking = file->tag.get_property("DISABLE_OPENGL_MASKING", disable_opengl_masking);
408 for(int i = 0; i < masks.size(); i++)
410 delete masks.values[i];
411 masks.values[i] = new SubMask(this, i);
415 while( !(result = file->read_tag()) ) {
416 if( file->tag.title_is("/AUTO") ) break;
417 if( file->tag.title_is("MASK") ) {
418 int no = file->tag.get_property("NUMBER", 0);
419 char name[BCTEXTLEN]; name[0] = 0;
420 file->tag.get_property("NAME", name);
421 if( !name[0] ) sprintf(name, "%d", no);
422 SubMask *mask = masks.values[no];
423 memset(mask->name, 0, sizeof(mask->name));
424 strncpy(mask->name, name, sizeof(mask->name));
431 void MaskAuto::copy(int64_t start, int64_t end, FileXML *file, int default_auto)
433 file->tag.set_title("AUTO");
434 file->tag.set_property("MODE", mode);
435 file->tag.set_property("VALUE", value);
436 file->tag.set_property("FEATHER", feather);
437 file->tag.set_property("APPLY_BEFORE_PLUGINS", apply_before_plugins);
438 file->tag.set_property("DISABLE_OPENGL_MASKING", disable_opengl_masking);
441 file->tag.set_property("POSITION", 0);
443 file->tag.set_property("POSITION", position - start);
445 file->append_newline();
447 for(int i = 0; i < masks.size(); i++)
449 //printf("MaskAuto::copy 1 %p %d %p\n", this, i, masks.values[i]);
450 masks.values[i]->copy(file);
451 //printf("MaskAuto::copy 10\n");
454 file->tag.set_title("/AUTO");
456 file->append_newline();
459 void MaskAuto::dump()
461 printf(" mode=%d value=%d\n", mode, value);
462 for(int i = 0; i < masks.size(); i++)
464 printf(" submask %d\n", i);
465 masks.values[i]->dump();
469 void MaskAuto::translate_submasks(float translate_x, float translate_y)
471 for(int i = 0; i < masks.size(); i++)
473 SubMask *mask = get_submask(i);
474 for (int j = 0; j < mask->points.total; j++)
476 mask->points.values[j]->x += translate_x;
477 mask->points.values[j]->y += translate_y;
482 void MaskAuto::scale_submasks(int orig_scale, int new_scale)
484 for(int i = 0; i < masks.size(); i++)
486 SubMask *mask = get_submask(i);
487 for (int j = 0; j < mask->points.total; j++)
489 float orig_x = mask->points.values[j]->x * orig_scale;
490 float orig_y = mask->points.values[j]->y * orig_scale;
491 mask->points.values[j]->x = orig_x / new_scale;
492 mask->points.values[j]->y = orig_y / new_scale;
494 orig_x = mask->points.values[j]->control_x1 * orig_scale;
495 orig_y = mask->points.values[j]->control_y1 * orig_scale;
496 mask->points.values[j]->control_x1 = orig_x / new_scale;
497 mask->points.values[j]->control_y1 = orig_y / new_scale;
499 orig_x = mask->points.values[j]->control_x2 * orig_scale;
500 orig_y = mask->points.values[j]->control_y2 * orig_scale;
501 mask->points.values[j]->control_x2 = orig_x / new_scale;
502 mask->points.values[j]->control_y2 = orig_y / new_scale;