prevent popup deactivation while button_down
[goodguy/history.git] / cinelerra-5.0 / cinelerra / maskauto.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  * 
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.
10  * 
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.
15  * 
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
19  * 
20  */
21
22 #include "clip.h"
23 #include "filexml.h"
24 #include "maskauto.h"
25 #include "maskautos.h"
26
27 #include <stdlib.h>
28 #include <string.h>
29
30
31
32
33 MaskPoint::MaskPoint()
34 {
35         x = 0;
36         y = 0;
37         control_x1 = 0;
38         control_y1 = 0;
39         control_x2 = 0;
40         control_y2 = 0;
41 }
42
43 void MaskPoint::copy_from(MaskPoint &ptr)
44 {
45         this->x = ptr.x;
46         this->y = ptr.y;
47         this->control_x1 = ptr.control_x1;
48         this->control_y1 = ptr.control_y1;
49         this->control_x2 = ptr.control_x2;
50         this->control_y2 = ptr.control_y2;
51 }
52
53 MaskPoint& MaskPoint::operator=(MaskPoint& ptr)
54 {
55         copy_from(ptr);
56         return *this;
57 }
58
59 int MaskPoint::operator==(MaskPoint& ptr)
60 {
61         return EQUIV(x, ptr.x) &&
62                 EQUIV(y, ptr.y) &&
63                 EQUIV(control_x1, ptr.control_x1) &&
64                 EQUIV(control_y1, ptr.control_y1) &&
65                 EQUIV(control_x2, ptr.control_x2) &&
66                 EQUIV(control_y2, ptr.control_y2);
67 }
68
69 SubMask::SubMask(MaskAuto *keyframe)
70 {
71         this->keyframe = keyframe;
72 }
73
74 SubMask::~SubMask()
75 {
76 }
77
78 int SubMask::equivalent(SubMask& ptr)
79 {
80         if(points.size() != ptr.points.size()) return 0;
81
82         for(int i = 0; i < points.size(); i++)
83         {
84                 if(!(*points.get(i) == *ptr.points.get(i)))
85                         return 0;
86         }
87         
88         return 1;
89 }
90
91
92 int SubMask::operator==(SubMask& ptr)
93 {
94         return equivalent(ptr);
95 }
96
97 void SubMask::copy_from(SubMask& ptr)
98 {
99         points.remove_all_objects();
100 //printf("SubMask::copy_from 1 %p %d\n", this, ptr.points.total);
101         for(int i = 0; i < ptr.points.total; i++)
102         {
103                 MaskPoint *point = new MaskPoint;
104                 *point = *ptr.points.values[i];
105                 points.append(point);
106         }
107 }
108
109 void SubMask::load(FileXML *file)
110 {
111         points.remove_all_objects();
112
113         int result = 0;
114         while(!result)
115         {
116                 result = file->read_tag();
117                 
118                 if(!result)
119                 {
120                         if(file->tag.title_is("/MASK"))
121                         {
122                                 result = 1;
123                         }
124                         else
125                         if(file->tag.title_is("POINT"))
126                         {
127                                 char string[BCTEXTLEN];
128                                 string[0] = 0;
129                                 file->read_text_until("/POINT", string, BCTEXTLEN);
130
131                                 MaskPoint *point = new MaskPoint;
132                                 char *ptr = string;
133 //printf("MaskAuto::load 1 %s\n", ptr);
134
135                                 point->x = atof(ptr);
136                                 ptr = strchr(ptr, ',');
137 //printf("MaskAuto::load 2 %s\n", ptr + 1);
138                                 if(ptr) 
139                                 {
140                                         point->y = atof(ptr + 1);
141                                         ptr = strchr(ptr + 1, ',');
142                                 
143                                         if(ptr)
144                                         {
145 //printf("MaskAuto::load 3 %s\n", ptr + 1);
146                                                 point->control_x1 = atof(ptr + 1);
147                                                 ptr = strchr(ptr + 1, ',');
148                                                 if(ptr)
149                                                 {
150 //printf("MaskAuto::load 4 %s\n", ptr + 1);
151                                                         point->control_y1 = atof(ptr + 1);
152                                                         ptr = strchr(ptr + 1, ',');
153                                                         if(ptr)
154                                                         {
155 //printf("MaskAuto::load 5 %s\n", ptr + 1);
156                                                                 point->control_x2 = atof(ptr + 1);
157                                                                 ptr = strchr(ptr + 1, ',');
158                                                                 if(ptr) point->control_y2 = atof(ptr + 1);
159                                                         }
160                                                 }
161                                         }
162                                         
163                                 }
164                                 points.append(point);
165                         }
166                 }
167         }
168 }
169
170 void SubMask::copy(FileXML *file)
171 {
172         if(points.total)
173         {
174                 file->tag.set_title("MASK");
175                 file->tag.set_property("NUMBER", keyframe->masks.number_of(this));
176                 file->append_tag();
177                 file->append_newline();
178
179                 for(int i = 0; i < points.total; i++)
180                 {
181                         file->append_newline();
182                         file->tag.set_title("POINT");
183                         file->append_tag();
184                         char string[BCTEXTLEN];
185 //printf("SubMask::copy 1 %p %d %p\n", this, i, points.values[i]);
186                         sprintf(string, "%.6e, %.6e, %.6e, %.6e, %.6e, %.6e", 
187                                 points.values[i]->x, 
188                                 points.values[i]->y, 
189                                 points.values[i]->control_x1, 
190                                 points.values[i]->control_y1, 
191                                 points.values[i]->control_x2, 
192                                 points.values[i]->control_y2);
193 //printf("SubMask::copy 2\n");
194                         file->append_text(string);
195                         file->tag.set_title("/POINT");
196                         file->append_tag();
197                 }
198                 file->append_newline();
199
200                 file->tag.set_title("/MASK");
201                 file->append_tag();
202                 file->append_newline();
203         }
204 }
205
206 void SubMask::dump()
207 {
208         for(int i = 0; i < points.total; i++)
209         {
210                 printf("          point=%d x=%.2f y=%.2f in_x=%.2f in_y=%.2f out_x=%.2f out_y=%.2f\n",
211                         i,
212                         points.values[i]->x, 
213                         points.values[i]->y, 
214                         points.values[i]->control_x1, 
215                         points.values[i]->control_y1, 
216                         points.values[i]->control_x2, 
217                         points.values[i]->control_y2);
218         }
219 }
220
221
222 MaskAuto::MaskAuto(EDL *edl, MaskAutos *autos)
223  : Auto(edl, autos)
224 {
225         mode = MASK_SUBTRACT_ALPHA;
226         feather = 0;
227         value = 100;
228
229 // We define a fixed number of submasks so that interpolation for each
230 // submask matches.
231
232         for(int i = 0; i < SUBMASKS; i++)
233                 masks.append(new SubMask(this));
234 }
235
236 MaskAuto::~MaskAuto()
237 {
238         masks.remove_all_objects();
239 }
240
241 int MaskAuto::operator==(Auto &that)
242 {
243         return identical((MaskAuto*)&that);
244 }
245
246
247
248 int MaskAuto::operator==(MaskAuto &that)
249 {
250         return identical((MaskAuto*)&that);
251 }
252
253
254 int MaskAuto::identical(MaskAuto *src)
255 {
256         if(value != src->value ||
257                 mode != src->mode ||
258                 feather != src->feather ||
259                 masks.size() != src->masks.size()) return 0;
260
261         for(int i = 0; i < masks.size(); i++)
262                 if(!(*masks.values[i] == *src->masks.values[i])) return 0;
263
264         return 1;
265 }
266
267 void MaskAuto::update_parameter(MaskAuto *ref, MaskAuto *src)
268 {
269         if(src->value != ref->value)
270         {
271                 this->value = src->value;
272         }
273
274         if(src->mode != ref->mode)
275         {
276                 this->mode = src->mode;
277         }
278
279         if(!EQUIV(src->feather, ref->feather))
280         {
281                 this->feather = src->feather;
282         }
283
284         for(int i = 0; i < masks.size(); i++)
285         {
286                 if(!src->get_submask(i)->equivalent(*ref->get_submask(i)))
287                         this->get_submask(i)->copy_from(*src->get_submask(i));
288         }
289 }
290
291 void MaskAuto::copy_from(Auto *src)
292 {
293         copy_from((MaskAuto*)src);
294 }
295
296 void MaskAuto::copy_from(MaskAuto *src)
297 {
298         Auto::copy_from(src);
299         copy_data(src);
300 }
301
302 void MaskAuto::copy_data(MaskAuto *src)
303 {
304         mode = src->mode;
305         feather = src->feather;
306         value = src->value;
307
308         masks.remove_all_objects();
309         for(int i = 0; i < src->masks.size(); i++)
310         {
311                 masks.append(new SubMask(this));
312                 masks.values[i]->copy_from(*src->masks.values[i]);
313         }
314 }
315
316
317 SubMask* MaskAuto::get_submask(int number)
318 {
319         CLAMP(number, 0, masks.size() - 1);
320         return masks.values[number];
321 }
322
323 void MaskAuto::get_points(ArrayList<MaskPoint*> *points, 
324         int submask)
325 {
326         points->remove_all_objects();
327         SubMask *submask_ptr = get_submask(submask);
328         for(int i = 0; i < submask_ptr->points.size(); i++)
329         {
330                 MaskPoint *point = new MaskPoint;
331                 point->copy_from(*submask_ptr->points.get(i));
332                 points->append(point);
333         }
334 }
335
336 void MaskAuto::set_points(ArrayList<MaskPoint*> *points, 
337         int submask)
338 {
339         SubMask *submask_ptr = get_submask(submask);
340         submask_ptr->points.remove_all_objects();
341         for(int i = 0; i < points->size(); i++)
342         {
343                 MaskPoint *point = new MaskPoint;
344                 point->copy_from(*points->get(i));
345                 submask_ptr->points.append(point);
346         }
347 }
348
349
350 void MaskAuto::load(FileXML *file)
351 {
352         mode = file->tag.get_property("MODE", mode);
353         feather = file->tag.get_property("FEATHER", feather);
354         value = file->tag.get_property("VALUE", value);
355         for(int i = 0; i < masks.size(); i++)
356         {
357                 delete masks.values[i];
358                 masks.values[i] = new SubMask(this);
359         }
360
361         int result = 0;
362         while(!result)
363         {
364                 result = file->read_tag();
365
366                 if(!result)
367                 {
368                         if(file->tag.title_is("/AUTO")) 
369                                 result = 1;
370                         else
371                         if(file->tag.title_is("MASK"))
372                         {
373                                 SubMask *mask = masks.values[file->tag.get_property("NUMBER", 0)];
374                                 mask->load(file);
375                         }
376                 }
377         }
378 //      dump();
379 }
380
381 void MaskAuto::copy(int64_t start, int64_t end, FileXML *file, int default_auto)
382 {
383         file->tag.set_title("AUTO");
384         file->tag.set_property("MODE", mode);
385         file->tag.set_property("VALUE", value);
386         file->tag.set_property("FEATHER", feather);
387         if(default_auto)
388                 file->tag.set_property("POSITION", 0);
389         else
390                 file->tag.set_property("POSITION", position - start);
391         file->append_tag();
392         file->append_newline();
393
394         for(int i = 0; i < masks.size(); i++)
395         {
396 //printf("MaskAuto::copy 1 %p %d %p\n", this, i, masks.values[i]);
397                 masks.values[i]->copy(file);
398 //printf("MaskAuto::copy 10\n");
399         }
400
401         file->append_newline();
402         file->tag.set_title("/AUTO");
403         file->append_tag();
404         file->append_newline();
405 }
406
407 void MaskAuto::dump()
408 {
409         printf("         mode=%d value=%d\n", mode, value);
410         for(int i = 0; i < masks.size(); i++)
411         {
412                 printf("         submask %d\n", i);
413                 masks.values[i]->dump();
414         }
415 }
416
417 void MaskAuto::translate_submasks(float translate_x, float translate_y)
418 {
419         for(int i = 0; i < masks.size(); i++)
420         {
421                 SubMask *mask = get_submask(i);
422                 for (int j = 0; j < mask->points.total; j++) 
423                 {
424                         mask->points.values[j]->x += translate_x;
425                         mask->points.values[j]->y += translate_y;
426                 }
427         }
428 }
429
430 void MaskAuto::scale_submasks(int orig_scale, int new_scale)
431 {
432         for(int i = 0; i < masks.size(); i++)
433         {
434                 SubMask *mask = get_submask(i);
435                 for (int j = 0; j < mask->points.total; j++) 
436                 {
437                         float orig_x = mask->points.values[j]->x * orig_scale;
438                         float orig_y = mask->points.values[j]->y * orig_scale;
439                         mask->points.values[j]->x = orig_x / new_scale;
440                         mask->points.values[j]->y = orig_y / new_scale;
441                         
442                         orig_x = mask->points.values[j]->control_x1 * orig_scale;
443                         orig_y = mask->points.values[j]->control_y1 * orig_scale;
444                         mask->points.values[j]->control_x1 = orig_x / new_scale;
445                         mask->points.values[j]->control_y1 = orig_y / new_scale;
446                         
447                         orig_x = mask->points.values[j]->control_x2 * orig_scale;
448                         orig_y = mask->points.values[j]->control_y2 * orig_scale;
449                         mask->points.values[j]->control_x2 = orig_x / new_scale;
450                         mask->points.values[j]->control_y2 = orig_y / new_scale;
451                 }
452         }
453 }
454
455