r1014: Enable horizontal scrolling with the mouse wheel by pressing Ctrl.
[cinelerra_cv/ct.git] / cinelerra / maskauto.C
blobd87a80cdf707263cb90e700b004020460f78339c
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, "%.7g, %.7g, %.7g, %.7g, %.7g, %.7g",
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;
195         apply_before_plugins = 0;
197 // We define a fixed number of submasks so that interpolation for each
198 // submask matches.
200         for(int i = 0; i < SUBMASKS; i++)
201                 masks.append(new SubMask(this));
204 MaskAuto::~MaskAuto()
206         masks.remove_all_objects();
209 int MaskAuto::operator==(Auto &that)
211         return identical((MaskAuto*)&that);
216 int MaskAuto::operator==(MaskAuto &that)
218         return identical((MaskAuto*)&that);
222 int MaskAuto::identical(MaskAuto *src)
224         if(value != src->value ||
225                 mode != src->mode ||
226                 feather != src->feather ||
227                 masks.total != src->masks.total ||
228                 apply_before_plugins != src->apply_before_plugins) return 0;
230         for(int i = 0; i < masks.total; i++)
231                 if(!(*masks.values[i] == *src->masks.values[i])) return 0;
233         return 1;
236 void MaskAuto::copy_from(Auto *src)
238         copy_from((MaskAuto*)src);
241 void MaskAuto::copy_from(MaskAuto *src)
243         Auto::copy_from(src);
245         mode = src->mode;
246         feather = src->feather;
247         value = src->value;
248         apply_before_plugins = src->apply_before_plugins;
250         masks.remove_all_objects();
251         for(int i = 0; i < src->masks.total; i++)
252         {
253                 masks.append(new SubMask(this));
254                 masks.values[i]->copy_from(*src->masks.values[i]);
255         }
259 int MaskAuto::interpolate_from(Auto *a1, Auto *a2, int64_t position) {
260         MaskAuto  *mask_auto1 = (MaskAuto *)a1;
261         MaskAuto  *mask_auto2 = (MaskAuto *)a2;
263         if (!mask_auto2 || mask_auto2->masks.total == 0) // if mask_auto == null, copy from first
264         {
265                 copy_from(mask_auto1);
266                 return 0;
267         }
268         this->mode = mask_auto1->mode;
269         this->feather = mask_auto1->feather;
270         this->value = mask_auto1->value;
271         this->apply_before_plugins = mask_auto1->apply_before_plugins;
272         this->position = position;
273         masks.remove_all_objects();
275         for(int i = 0; 
276                 i < mask_auto1->masks.total; 
277                 i++)
278         {
279                 SubMask *new_submask = new SubMask(this);
280                 masks.append(new_submask);
281                 SubMask *mask1 = mask_auto1->masks.values[i];
282                 SubMask *mask2 = mask_auto2->masks.values[i];
284                 // just in case, should never happen
285                 int total_points = MIN(mask1->points.total, mask2->points.total);
286                 for(int j = 0; j < total_points; j++)
287                 {
288                         MaskPoint *point = new MaskPoint;
289                         MaskAutos::avg_points(point, 
290                                 mask1->points.values[j], 
291                                 mask2->points.values[j],
292                                 position,
293                                 mask_auto1->position,
294                                 mask_auto2->position);
295                         new_submask->points.append(point);
296                 }
298         }
304 SubMask* MaskAuto::get_submask(int number)
306         CLAMP(number, 0, masks.total - 1);
307         return masks.values[number];
310 void MaskAuto::load(FileXML *file)
312         mode = file->tag.get_property("MODE", mode);
313         feather = file->tag.get_property("FEATHER", feather);
314         value = file->tag.get_property("VALUE", value);
315         apply_before_plugins = file->tag.get_property("APPLY_BEFORE_PLUGINS", apply_before_plugins);
316         for(int i = 0; i < masks.total; i++)
317         {
318                 delete masks.values[i];
319                 masks.values[i] = new SubMask(this);
320         }
322         int result = 0;
323         while(!result)
324         {
325                 result = file->read_tag();
327                 if(!result)
328                 {
329                         if(file->tag.title_is("/AUTO")) 
330                                 result = 1;
331                         else
332                         if(file->tag.title_is("MASK"))
333                         {
334                                 SubMask *mask = masks.values[file->tag.get_property("NUMBER", 0)];
335                                 mask->load(file);
336                         }
337                 }
338         }
339 //      dump();
342 void MaskAuto::copy(int64_t start, int64_t end, FileXML *file, int default_auto)
344         file->tag.set_title("AUTO");
345         file->tag.set_property("MODE", mode);
346         file->tag.set_property("VALUE", value);
347         file->tag.set_property("FEATHER", feather);
348         file->tag.set_property("APPLY_BEFORE_PLUGINS", apply_before_plugins);
350         if(default_auto)
351                 file->tag.set_property("POSITION", 0);
352         else
353                 file->tag.set_property("POSITION", position - start);
354         file->append_tag();
355         file->append_newline();
357         for(int i = 0; i < masks.total; i++)
358         {
359 //printf("MaskAuto::copy 1 %p %d %p\n", this, i, masks.values[i]);
360                 masks.values[i]->copy(file);
361 //printf("MaskAuto::copy 10\n");
362         }
364         file->append_newline();
365         file->tag.set_title("/AUTO");
366         file->append_tag();
367         file->append_newline();
370 void MaskAuto::dump()
372         printf("         mode=%d value=%d\n", mode, value);
373         for(int i = 0; i < masks.total; i++)
374         {
375                 printf("         submask %d\n", i);
376                 masks.values[i]->dump();
377         }
380 void MaskAuto::translate_submasks(float translate_x, float translate_y)
382         for(int i = 0; i < masks.total; i++)
383         {
384                 SubMask *mask = get_submask(i);
385                 for (int j = 0; j < mask->points.total; j++) 
386                 {
387                         mask->points.values[j]->x += translate_x;
388                         mask->points.values[j]->y += translate_y;
389                 }
390         }