r665: Merged the official release 2.0.
[cinelerra_cv.git] / cinelerra / maskauto.C
blob7bb5bc2acd040410202b5e534750085d590cc8f6
1 #include "clip.h"
2 #include "filexml.h"
3 #include "maskauto.h"
4 #include "maskautos.h"
6 #include <stdlib.h>
7 #include <string.h>
12 MaskPoint::MaskPoint()
14         x = 0;
15         y = 0;
16         control_x1 = 0;
17         control_y1 = 0;
18         control_x2 = 0;
19         control_y2 = 0;
22 MaskPoint& MaskPoint::operator=(MaskPoint& ptr)
24         this->x = ptr.x;
25         this->y = ptr.y;
26         this->control_x1 = ptr.control_x1;
27         this->control_y1 = ptr.control_y1;
28         this->control_x2 = ptr.control_x2;
29         this->control_y2 = ptr.control_y2;
32 int MaskPoint::operator==(MaskPoint& ptr)
34         return EQUIV(x, ptr.x) &&
35                 EQUIV(y, ptr.y) &&
36                 EQUIV(control_x1, ptr.control_x1) &&
37                 EQUIV(control_y1, ptr.control_y1) &&
38                 EQUIV(control_x2, ptr.control_x2) &&
39                 EQUIV(control_y2, ptr.control_y2);
42 SubMask::SubMask(MaskAuto *keyframe)
44         this->keyframe = keyframe;
47 SubMask::~SubMask()
51 int SubMask::operator==(SubMask& ptr)
53         if(points.total != ptr.points.total) return 0;
55         for(int i = 0; i < points.total; i++)
56         {
57                 if(!(*points.values[i] == *ptr.points.values[i]))
58                         return 0;
59         }
60         
61         return 1;
64 void SubMask::copy_from(SubMask& ptr)
66         points.remove_all_objects();
67 //printf("SubMask::copy_from 1 %p %d\n", this, ptr.points.total);
68         for(int i = 0; i < ptr.points.total; i++)
69         {
70                 MaskPoint *point = new MaskPoint;
71                 *point = *ptr.points.values[i];
72                 points.append(point);
73         }
76 void SubMask::load(FileXML *file)
78         points.remove_all_objects();
80         int result = 0;
81         while(!result)
82         {
83                 result = file->read_tag();
84                 
85                 if(!result)
86                 {
87                         if(file->tag.title_is("/MASK"))
88                         {
89                                 result = 1;
90                         }
91                         else
92                         if(file->tag.title_is("POINT"))
93                         {
94                                 char string[BCTEXTLEN];
95                                 string[0] = 0;
96                                 file->read_text_until("/POINT", string, BCTEXTLEN);
98                                 MaskPoint *point = new MaskPoint;
99                                 char *ptr = string;
100 //printf("MaskAuto::load 1 %s\n", ptr);
102                                 point->x = atof(ptr);
103                                 ptr = strchr(ptr, ',');
104 //printf("MaskAuto::load 2 %s\n", ptr + 1);
105                                 if(ptr) 
106                                 {
107                                         point->y = atof(ptr + 1);
108                                         ptr = strchr(ptr + 1, ',');
109                                 
110                                         if(ptr)
111                                         {
112 //printf("MaskAuto::load 3 %s\n", ptr + 1);
113                                                 point->control_x1 = atof(ptr + 1);
114                                                 ptr = strchr(ptr + 1, ',');
115                                                 if(ptr)
116                                                 {
117 //printf("MaskAuto::load 4 %s\n", ptr + 1);
118                                                         point->control_y1 = atof(ptr + 1);
119                                                         ptr = strchr(ptr + 1, ',');
120                                                         if(ptr)
121                                                         {
122 //printf("MaskAuto::load 5 %s\n", ptr + 1);
123                                                                 point->control_x2 = atof(ptr + 1);
124                                                                 ptr = strchr(ptr + 1, ',');
125                                                                 if(ptr) point->control_y2 = atof(ptr + 1);
126                                                         }
127                                                 }
128                                         }
129                                         
130                                 }
131                                 points.append(point);
132                         }
133                 }
134         }
137 void SubMask::copy(FileXML *file)
139         if(points.total)
140         {
141                 file->tag.set_title("MASK");
142                 file->tag.set_property("NUMBER", keyframe->masks.number_of(this));
143                 file->append_tag();
144                 file->append_newline();
146                 for(int i = 0; i < points.total; i++)
147                 {
148                         file->append_newline();
149                         file->tag.set_title("POINT");
150                         file->append_tag();
151                         char string[BCTEXTLEN];
152 //printf("SubMask::copy 1 %p %d %p\n", this, i, points.values[i]);
153                         sprintf(string, "%.6e, %.6e, %.6e, %.6e, %.6e, %.6e", 
154                                 points.values[i]->x, 
155                                 points.values[i]->y, 
156                                 points.values[i]->control_x1, 
157                                 points.values[i]->control_y1, 
158                                 points.values[i]->control_x2, 
159                                 points.values[i]->control_y2);
160 //printf("SubMask::copy 2\n");
161                         file->append_text(string);
162                         file->tag.set_title("/POINT");
163                         file->append_tag();
164                 }
165                 file->append_newline();
167                 file->tag.set_title("/MASK");
168                 file->append_tag();
169                 file->append_newline();
170         }
173 void SubMask::dump()
175         for(int i = 0; i < points.total; i++)
176         {
177                 printf("          point=%d x=%.2f y=%.2f in_x=%.2f in_y=%.2f out_x=%.2f out_y=%.2f\n",
178                         i,
179                         points.values[i]->x, 
180                         points.values[i]->y, 
181                         points.values[i]->control_x1, 
182                         points.values[i]->control_y1, 
183                         points.values[i]->control_x2, 
184                         points.values[i]->control_y2);
185         }
189 MaskAuto::MaskAuto(EDL *edl, MaskAutos *autos)
190  : Auto(edl, autos)
192         mode = MASK_SUBTRACT_ALPHA;
193         feather = 0;
194         value = 100;
196 // We define a fixed number of submasks so that interpolation for each
197 // submask matches.
199         for(int i = 0; i < SUBMASKS; i++)
200                 masks.append(new SubMask(this));
203 MaskAuto::~MaskAuto()
205         masks.remove_all_objects();
208 int MaskAuto::operator==(Auto &that)
210         return identical((MaskAuto*)&that);
215 int MaskAuto::operator==(MaskAuto &that)
217         return identical((MaskAuto*)&that);
221 int MaskAuto::identical(MaskAuto *src)
223         if(value != src->value ||
224                 mode != src->mode ||
225                 feather != src->feather ||
226                 masks.total != src->masks.total) return 0;
228         for(int i = 0; i < masks.total; i++)
229                 if(!(*masks.values[i] == *src->masks.values[i])) return 0;
231         return 1;
234 void MaskAuto::copy_from(Auto *src)
236         copy_from((MaskAuto*)src);
239 void MaskAuto::copy_from(MaskAuto *src)
241         Auto::copy_from(src);
243         mode = src->mode;
244         feather = src->feather;
245         value = src->value;
247         masks.remove_all_objects();
248         for(int i = 0; i < src->masks.total; i++)
249         {
250                 masks.append(new SubMask(this));
251                 masks.values[i]->copy_from(*src->masks.values[i]);
252         }
256 int MaskAuto::interpolate_from(Auto *a1, Auto *a2, int64_t position) {
257         MaskAuto  *mask_auto1 = (MaskAuto *)a1;
258         MaskAuto  *mask_auto2 = (MaskAuto *)a2;
260         if (!mask_auto2 || mask_auto2->masks.total == 0) // if mask_auto == null, copy from first
261         {
262                 copy_from(mask_auto1);
263                 return 0;
264         }
265         this->mode = mask_auto1->mode;
266         this->feather = mask_auto1->feather;
267         this->value = mask_auto1->value;
268         this->position = position;
269         masks.remove_all_objects();
271         for(int i = 0; 
272                 i < mask_auto1->masks.total; 
273                 i++)
274         {
275                 SubMask *new_submask = new SubMask(this);
276                 masks.append(new_submask);
277                 SubMask *mask1 = mask_auto1->masks.values[i];
278                 SubMask *mask2 = mask_auto2->masks.values[i];
280                 // just in case, should never happen
281                 int total_points = MIN(mask1->points.total, mask2->points.total);
282                 for(int j = 0; j < total_points; j++)
283                 {
284                         MaskPoint *point = new MaskPoint;
285                         MaskAutos::avg_points(point, 
286                                 mask1->points.values[j], 
287                                 mask2->points.values[j],
288                                 position,
289                                 mask_auto1->position,
290                                 mask_auto2->position);
291                         new_submask->points.append(point);
292                 }
294         }
300 SubMask* MaskAuto::get_submask(int number)
302         CLAMP(number, 0, masks.total - 1);
303         return masks.values[number];
306 void MaskAuto::load(FileXML *file)
308         mode = file->tag.get_property("MODE", mode);
309         feather = file->tag.get_property("FEATHER", feather);
310         value = file->tag.get_property("VALUE", value);
311         for(int i = 0; i < masks.total; i++)
312         {
313                 delete masks.values[i];
314                 masks.values[i] = new SubMask(this);
315         }
317         int result = 0;
318         while(!result)
319         {
320                 result = file->read_tag();
322                 if(!result)
323                 {
324                         if(file->tag.title_is("/AUTO")) 
325                                 result = 1;
326                         else
327                         if(file->tag.title_is("MASK"))
328                         {
329                                 SubMask *mask = masks.values[file->tag.get_property("NUMBER", 0)];
330                                 mask->load(file);
331                         }
332                 }
333         }
334 //      dump();
337 void MaskAuto::copy(int64_t start, int64_t end, FileXML *file, int default_auto)
339         file->tag.set_title("AUTO");
340         file->tag.set_property("MODE", mode);
341         file->tag.set_property("VALUE", value);
342         file->tag.set_property("FEATHER", feather);
343         if(default_auto)
344                 file->tag.set_property("POSITION", 0);
345         else
346                 file->tag.set_property("POSITION", position - start);
347         file->append_tag();
348         file->append_newline();
350         for(int i = 0; i < masks.total; i++)
351         {
352 //printf("MaskAuto::copy 1 %p %d %p\n", this, i, masks.values[i]);
353                 masks.values[i]->copy(file);
354 //printf("MaskAuto::copy 10\n");
355         }
357         file->append_newline();
358         file->tag.set_title("/AUTO");
359         file->append_tag();
360         file->append_newline();
363 void MaskAuto::dump()
365         printf("         mode=%d value=%d\n", mode, value);
366         for(int i = 0; i < masks.total; i++)
367         {
368                 printf("         submask %d\n", i);
369                 masks.values[i]->dump();
370         }
373 void MaskAuto::translate_submasks(float translate_x, float translate_y)
375         for(int i = 0; i < masks.total; i++)
376         {
377                 SubMask *mask = get_submask(i);
378                 for (int j = 0; j < mask->points.total; j++) 
379                 {
380                         mask->points.values[j]->x += translate_x;
381                         mask->points.values[j]->y += translate_y;
382                 }
383         }