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