initial commit
[goodguy/history.git] / cinelerra-5.0 / cinelerra / maskautos.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 "automation.inc"
23 #include "clip.h"
24 #include "edl.h"
25 #include "format.inc"
26 #include "localsession.h"
27 #include "maskauto.h"
28 #include "maskautos.h"
29 #include "track.h"
30 #include "transportque.inc"
31
32
33
34
35 MaskAutos::MaskAutos(EDL *edl, 
36         Track *track)
37  : Autos(edl, track)
38 {
39         type = AUTOMATION_TYPE_MASK;
40 }
41
42 MaskAutos::~MaskAutos()
43 {
44 }
45
46
47
48
49 void MaskAutos::update_parameter(MaskAuto *src)
50 {
51         double selection_start = edl->local_session->get_selectionstart(0);
52         double selection_end = edl->local_session->get_selectionend(0);
53
54 // Selection is always aligned to frame for masks
55
56 // Create new keyframe if auto keyframes or replace entire keyframe.
57         if(selection_start == selection_end)
58         {
59 // Search for keyframe to write to
60                 MaskAuto *dst = (MaskAuto*)get_auto_for_editing();
61
62                 dst->copy_data(src);
63         }
64         else
65 // Replace changed parameter in all selected keyframes.
66         {
67 // Search all keyframes in selection but don't create a new one.
68                 int64_t start = track->to_units(selection_start, 0);
69                 int64_t end = track->to_units(selection_end, 0);
70                 Auto *current_auto = 0;
71                 MaskAuto *current = 0;
72                 current = (MaskAuto*)get_prev_auto(start, 
73                         PLAY_FORWARD, 
74                         current_auto, 
75                         1);
76
77 // The first one determines the changed parameters since it is the one displayed
78 // in the GUI.
79                 MaskAuto *first = current;
80
81 // Update the first one last, so it is available for comparisons to the changed one.
82                 for(current = (MaskAuto*)NEXT; 
83                         current && current->position < end; 
84                         current = (MaskAuto*)NEXT)
85                 {
86                         current->update_parameter(first, 
87                                 src);
88                 }
89                 first->copy_data(src);
90         }
91 }
92
93
94
95 void MaskAutos::get_points(ArrayList<MaskPoint*> *points, 
96         int submask, 
97         int64_t position, 
98         int direction)
99 {
100         MaskAuto *begin = 0, *end = 0;
101         position = (direction == PLAY_FORWARD) ? position : (position - 1);
102
103 // Get auto before and after position
104         for(MaskAuto* current = (MaskAuto*)last; 
105                 current; 
106                 current = (MaskAuto*)PREVIOUS)
107         {
108                 if(current->position <= position)
109                 {
110                         begin = current;
111                         end = NEXT ? (MaskAuto*)NEXT : current;
112                         break;
113                 }
114         }
115
116 // Nothing before position found
117         if(!begin)
118         {
119                 begin = end = (MaskAuto*)first;
120         }
121
122 // Nothing after position found
123         if(!begin)
124         {
125                 begin = end = (MaskAuto*)default_auto;
126         }
127
128
129         SubMask *mask1 = begin->get_submask(submask);
130         SubMask *mask2 = end->get_submask(submask);
131
132         points->remove_all_objects();
133         int total_points = MAX(mask1->points.size(), mask2->points.size());
134         for(int i = 0; i < total_points; i++)
135         {
136                 MaskPoint *point = new MaskPoint;
137                 MaskPoint point1;
138                 int need_point1 = 1;
139                 MaskPoint point2;
140                 int need_point2 = 1;
141
142                 if(i < mask1->points.size())
143                 {
144                         point1.copy_from(*mask1->points.get(i));
145                         need_point1 = 0;
146                 }
147
148                 if(i < mask2->points.size())
149                 {
150                         point2.copy_from(*mask2->points.get(i));
151                         need_point2 = 0;
152                 }
153
154                 if(need_point1) point1.copy_from(point2);
155                 if(need_point2) point2.copy_from(point1);
156
157                 avg_points(point, 
158                         &point1, 
159                         &point2,
160                         position,
161                         begin->position,
162                         end->position);
163                 points->append(point);
164         }
165 }
166
167
168 float MaskAutos::get_feather(int64_t position, int direction)
169 {
170         Auto *begin = 0, *end = 0;
171         position = (direction == PLAY_FORWARD) ? position : (position - 1);
172
173         get_prev_auto(position, PLAY_FORWARD, begin, 1);
174         get_next_auto(position, PLAY_FORWARD, end, 1);
175
176         double weight = 0.0;
177         if(end->position != begin->position) 
178                 weight = (double)(position - begin->position) / (end->position - begin->position);
179
180         return ((MaskAuto*)begin)->feather * (1.0 - weight) + ((MaskAuto*)end)->feather * weight;
181 }
182
183 int MaskAutos::get_value(int64_t position, int direction)
184 {
185         Auto *begin = 0, *end = 0;
186         position = (direction == PLAY_FORWARD) ? position : (position - 1);
187
188         get_prev_auto(position, PLAY_FORWARD, begin, 1);
189         get_next_auto(position, PLAY_FORWARD, end, 1);
190
191         double weight = 0.0;
192         if(end->position != begin->position) 
193                 weight = (double)(position - begin->position) / (end->position - begin->position);
194
195         int result = (int)((double)((MaskAuto*)begin)->value * (1.0 - weight) + 
196                 (double)((MaskAuto*)end)->value * weight + 0.5);
197 // printf("MaskAutos::get_value %d %d %f %d %f %d\n",
198 // __LINE__,
199 // ((MaskAuto*)begin)->value,
200 // 1.0 - weight,
201 // ((MaskAuto*)end)->value,
202 // weight,
203 // result);
204         return result;
205 }
206
207
208 void MaskAutos::avg_points(MaskPoint *output, 
209                 MaskPoint *input1, 
210                 MaskPoint *input2, 
211                 int64_t output_position,
212                 int64_t position1, 
213                 int64_t position2)
214 {
215         if(position2 == position1)
216         {
217                 *output = *input1;
218         }
219         else
220         {
221                 float fraction2 = (float)(output_position - position1) / (position2 - position1);
222                 float fraction1 = 1 - fraction2;
223                 output->x = input1->x * fraction1 + input2->x * fraction2;
224                 output->y = input1->y * fraction1 + input2->y * fraction2;
225                 output->control_x1 = input1->control_x1 * fraction1 + input2->control_x1 * fraction2;
226                 output->control_y1 = input1->control_y1 * fraction1 + input2->control_y1 * fraction2;
227                 output->control_x2 = input1->control_x2 * fraction1 + input2->control_x2 * fraction2;
228                 output->control_y2 = input1->control_y2 * fraction1 + input2->control_y2 * fraction2;
229         }
230         
231 }
232
233
234 Auto* MaskAutos::new_auto()
235 {
236         return new MaskAuto(edl, this);
237 }
238
239 void MaskAutos::dump()
240 {
241         printf("        MaskAutos::dump %p\n", this);
242         printf("        Default: position " _LD " submasks %d\n", 
243                 default_auto->position, 
244                 ((MaskAuto*)default_auto)->masks.total);
245         ((MaskAuto*)default_auto)->dump();
246         for(Auto* current = first; current; current = NEXT)
247         {
248                 printf("        position " _LD " masks %d\n", 
249                         current->position, 
250                         ((MaskAuto*)current)->masks.total);
251                 ((MaskAuto*)current)->dump();
252         }
253 }
254
255 int MaskAutos::mask_exists(int64_t position, int direction)
256 {
257         Auto *current = 0;
258         position = (direction == PLAY_FORWARD) ? position : (position - 1);
259
260         MaskAuto* keyframe = (MaskAuto*)get_prev_auto(position, direction, current);
261
262
263
264         for(int i = 0; i < keyframe->masks.total; i++)
265         {
266                 SubMask *mask = keyframe->get_submask(i);
267                 if(mask->points.total > 1) 
268                         return 1;
269         }
270         return 0;
271 }
272
273 int MaskAutos::total_submasks(int64_t position, int direction)
274 {
275         position = (direction == PLAY_FORWARD) ? position : (position - 1);
276         for(MaskAuto* current = (MaskAuto*)last; 
277                 current; 
278                 current = (MaskAuto*)PREVIOUS)
279         {
280                 if(current->position <= position)
281                 {
282                         return current->masks.total;
283                 }
284         }
285
286         return ((MaskAuto*)default_auto)->masks.total;
287 }
288
289
290 void MaskAutos::translate_masks(float translate_x, float translate_y)
291 {
292         ((MaskAuto *)default_auto)->translate_submasks(translate_x, translate_y);
293         for(MaskAuto* current = (MaskAuto*)first; 
294                 current; 
295                 current = (MaskAuto*)NEXT)
296         {
297                 current->translate_submasks(translate_x, translate_y);
298                 for(int i = 0; i < current->masks.total; i++)
299                 {
300                         SubMask *mask = current->get_submask(i);
301                         for (int j = 0; j < mask->points.total; j++) 
302                         {
303                                 mask->points.values[j]->x += translate_x;
304                                 mask->points.values[j]->y += translate_y;
305                                 printf("mpx: %f, mpy:%f\n",mask->points.values[j]->x,mask->points.values[j]->y);
306                         }
307                 }
308                 
309         }
310 }
311