prevent popup deactivation while button_down
[goodguy/history.git] / cinelerra-5.0 / cinelerra / floatautos.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 "filexml.h"
27 #include "floatauto.h"
28 #include "floatautos.h"
29 #include "format.inc"
30 #include "track.h"
31 #include "localsession.h"
32 #include "transportque.inc"
33
34 FloatAutos::FloatAutos(EDL *edl,
35                                 Track *track, 
36                                 float default_)
37  : Autos(edl, track)
38 {
39         this->default_ = default_;
40         type = AUTOMATION_TYPE_FLOAT;
41 }
42
43 FloatAutos::~FloatAutos()
44 {
45 }
46
47 void FloatAutos::set_automation_mode(int64_t start, int64_t end, int mode)
48 {
49         FloatAuto *current = (FloatAuto*)first;
50         while(current)
51         {
52                 //FloatAuto *previous_auto = (FloatAuto*)PREVIOUS;
53                 //FloatAuto *next_auto = (FloatAuto*)NEXT;
54
55 // Is current auto in range?            
56                 if(current->position >= start && current->position < end)
57                 {
58                         current->mode = mode;
59 //                      float current_value = current->value;
60 // 
61 // // Determine whether to set the control in point.
62 //                      if(previous_auto && previous_auto->position >= start)
63 //                      {
64 //                              float previous_value = previous_auto->value;
65 //                              current->control_in_value = (previous_value - current_value) / 6.0;
66 //                      }
67 // 
68 // // Determine whether to set the control out point
69 //                      if(next_auto && next_auto->position < end)
70 //                      {
71 //                              float next_value = next_auto->value;
72 //                              current->control_out_value = (next_value - current_value) / 6.0;
73 //                      }
74                 }
75                 current = (FloatAuto*)NEXT;
76         }
77 }
78
79 int FloatAutos::draw_joining_line(BC_SubWindow *canvas, int vertical, int center_pixel, int x1, int y1, int x2, int y2)
80 {
81         if(vertical)
82                 canvas->draw_line(center_pixel - y1, x1, center_pixel - y2, x2);
83         else
84                 canvas->draw_line(x1, center_pixel + y1, x2, center_pixel + y2);
85         return 0;
86 }
87
88
89 Auto* FloatAutos::new_auto()
90 {
91         FloatAuto *result = new FloatAuto(edl, this);
92         result->value = default_;
93         return result;
94 }
95
96 int FloatAutos::get_testy(float slope, int cursor_x, int ax, int ay)
97 {
98         return (int)(slope * (cursor_x - ax)) + ay;
99 }
100
101 int FloatAutos::automation_is_constant(int64_t start, 
102         int64_t length, 
103         int direction,
104         double &constant)
105 {
106         int total_autos = total();
107         int64_t end;
108
109         if(direction == PLAY_FORWARD)
110         {
111                 end = start + length;
112         }
113         else
114         {
115                 end = start + 1;
116                 start -= length;
117         }
118
119
120 // No keyframes on track
121         if(total_autos == 0)
122         {
123                 constant = ((FloatAuto*)default_auto)->value;
124                 return 1;
125         }
126         else
127 // Only one keyframe on track.
128         if(total_autos == 1)
129         {
130                 constant = ((FloatAuto*)first)->value;
131 //printf("FloatAutos::automation_is_constant %d\n", __LINE__);
132                 return 1;
133         }
134         else
135 // Last keyframe is before region
136         if(last->position <= start)
137         {
138                 constant = ((FloatAuto*)last)->value;
139 //printf("FloatAutos::automation_is_constant %d\n", __LINE__);
140                 return 1;
141         }
142         else
143 // First keyframe is after region
144         if(first->position > end)
145         {
146                 constant = ((FloatAuto*)first)->value;
147 //printf("FloatAutos::automation_is_constant %d\n", __LINE__);
148                 return 1;
149         }
150
151 // Scan sequentially
152         int64_t prev_position = -1;
153         for(Auto *current = first; current; current = NEXT)
154         {
155                 int test_current_next = 0;
156                 int test_previous_current = 0;
157                 FloatAuto *float_current = (FloatAuto*)current;
158
159 // keyframes before and after region but not in region
160                 if(prev_position >= 0 &&
161                         prev_position < start && 
162                         current->position >= end)
163                 {
164 // Get value now in case change doesn't occur
165                         constant = float_current->value;
166                         test_previous_current = 1;
167                 }
168                 prev_position = current->position;
169
170 // Keyframe occurs in the region
171                 if(!test_previous_current &&
172                         current->position < end && 
173                         current->position >= start)
174                 {
175
176 // Get value now in case change doesn't occur
177                         constant = float_current->value;
178
179 // Keyframe has neighbor
180                         if(current->previous)
181                         {
182                                 test_previous_current = 1;
183                         }
184
185                         if(current->next)
186                         {
187                                 test_current_next = 1;
188                         }
189                 }
190
191                 if(test_current_next)
192                 {
193 //printf("FloatAutos::automation_is_constant %d\n", __LINE__);
194                         FloatAuto *float_next = (FloatAuto*)current->next;
195
196 // Change occurs between keyframes
197                         if(!EQUIV(float_current->value, float_next->value) ||
198                                 ((float_current->mode != Auto::LINEAR ||
199                                         float_next->mode != Auto::LINEAR) &&
200                                 (!EQUIV(float_current->control_out_value, 0) ||
201                                         !EQUIV(float_next->control_in_value, 0))))
202                         {
203 //printf("FloatAutos::automation_is_constant %d\n", __LINE__);
204                                 return 0;
205                         }
206                 }
207
208                 if(test_previous_current)
209                 {
210                         FloatAuto *float_previous = (FloatAuto*)current->previous;
211
212 // Change occurs between keyframes if values differ or are joined by a curve.
213 //printf("FloatAutos::automation_is_constant %d\n", __LINE__);
214                         if(!EQUIV(float_current->value, float_previous->value) ||
215                                 ((float_current->mode != Auto::LINEAR ||
216                                         float_previous->mode != Auto::LINEAR) &&
217                                 (!EQUIV(float_current->control_out_value, 0) ||
218                                         !EQUIV(float_previous->control_in_value, 0))))
219                         {
220 // printf("FloatAutos::automation_is_constant %d %d %d %f %f %f %f\n", 
221 // start, 
222 // float_previous->position, 
223 // float_current->position, 
224 // float_previous->value, 
225 // float_current->value, 
226 // float_previous->control_out_value, 
227 // float_current->control_in_value);
228 //printf("FloatAutos::automation_is_constant %d\n", __LINE__);
229                                 return 0;
230                         }
231                 }
232         }
233 //printf("FloatAutos::automation_is_constant %d\n", __LINE__);
234
235 // Got nothing that changes in the region.
236         return 1;
237 }
238
239 double FloatAutos::get_automation_constant(int64_t start, int64_t end)
240 {
241         Auto *current_auto, *before = 0, *after = 0;
242         
243 // quickly get autos just outside range 
244         get_neighbors(start, end, &before, &after);
245
246 // no auto before range so use first
247         if(before)
248                 current_auto = before;
249         else
250                 current_auto = first;
251
252 // no autos at all so use default value
253         if(!current_auto) current_auto = default_auto;
254
255         return ((FloatAuto*)current_auto)->value;
256 }
257
258
259 float FloatAutos::get_value(int64_t position, 
260         int direction, 
261         FloatAuto* &previous, 
262         FloatAuto* &next)
263 {
264 // Calculate bezier equation at position
265         float y0, y1, y2, y3;
266         float t;
267
268         previous = (FloatAuto*)get_prev_auto(position, direction, (Auto* &)previous, 0);
269         next = (FloatAuto*)get_next_auto(position, direction, (Auto* &)next, 0);
270
271 // Constant
272         if(!next && !previous) return ((FloatAuto*)default_auto)->value;
273         if(!previous) return next->value;
274         if(!next) return previous->value;
275         if(next == previous) return previous->value;
276
277         if(direction == PLAY_FORWARD)
278         {
279                 if(EQUIV(previous->value, next->value))
280                 {
281                         if((previous->mode == Auto::LINEAR &&
282                                 next->mode == Auto::LINEAR) ||
283                                 (EQUIV(previous->control_out_value, 0) &&
284                                 EQUIV(next->control_in_value, 0)))
285                         {
286                                 return previous->value;
287                         }
288                 }
289         }
290         else
291         if(direction == PLAY_REVERSE)
292         {
293                 if(EQUIV(previous->value, next->value))
294                 {
295                         if((previous->mode == Auto::LINEAR &&
296                                 next->mode == Auto::LINEAR) ||
297                                 (EQUIV(previous->control_in_value, 0) &&
298                                 EQUIV(next->control_out_value, 0)))
299                         {
300                                 return previous->value;
301                         }
302                 }
303         }
304
305
306 // Interpolate
307         y0 = previous->value;
308         y3 = next->value;
309
310         if(direction == PLAY_FORWARD)
311         {
312 // division by 0
313                 if(next->position - previous->position == 0) return previous->value;
314                 y1 = previous->value + previous->control_out_value * 2;
315                 y2 = next->value + next->control_in_value * 2;
316                 t = (double)(position - previous->position) / 
317                         (next->position - previous->position);
318         }
319         else
320         {
321 // division by 0
322                 if(previous->position - next->position == 0) return previous->value;
323                 y1 = previous->value + previous->control_in_value * 2;
324                 y2 = next->value + next->control_out_value * 2;
325                 t = (double)(previous->position - position) / 
326                         (previous->position - next->position);
327         }
328
329         float result = 0;
330         if(previous->mode == Auto::LINEAR &&
331                 next->mode == Auto::LINEAR)
332         {
333                 result = previous->value + t * (next->value - previous->value);
334         }
335         else
336         {
337                 float tpow2 = t * t;
338                 float tpow3 = t * t * t;
339                 float invt = 1 - t;
340                 float invtpow2 = invt * invt;
341                 float invtpow3 = invt * invt * invt;
342
343                 result = (  invtpow3 * y0
344                         + 3 * t     * invtpow2 * y1
345                         + 3 * tpow2 * invt     * y2 
346                         +     tpow3            * y3);
347 //printf("FloatAutos::get_value %f %f %d %d %d %d\n", result, t, direction, position, previous->position, next->position);
348         }
349
350         return result;
351 }
352
353
354
355 void FloatAutos::get_extents(float *min, 
356         float *max,
357         int *coords_undefined,
358         int64_t unit_start,
359         int64_t unit_end)
360 {
361         if(!edl)
362         {
363                 printf("FloatAutos::get_extents edl == NULL\n");
364                 return;
365         }
366
367         if(!track)
368         {
369                 printf("FloatAutos::get_extents track == NULL\n");
370                 return;
371         }
372
373 // Use default auto
374         if(!first)
375         {
376                 FloatAuto *current = (FloatAuto*)default_auto;
377                 if(*coords_undefined)
378                 {
379                         *min = *max = current->value;
380                         *coords_undefined = 0;
381                 }
382
383                 *min = MIN(current->value, *min);
384                 *max = MAX(current->value, *max);
385         }
386
387 // Test all handles
388         for(FloatAuto *current = (FloatAuto*)first; current; current = (FloatAuto*)NEXT)
389         {
390                 if(current->position >= unit_start && current->position < unit_end)
391                 {
392                         if(*coords_undefined)
393                         {
394                                 *min = *max = current->value;
395                                 *coords_undefined = 0;
396                         }
397                         
398                         *min = MIN(current->value, *min);
399                         *min = MIN(current->value + current->control_in_value, *min);
400                         *min = MIN(current->value + current->control_out_value, *min);
401
402                         *max = MAX(current->value, *max);
403                         *max = MAX(current->value + current->control_in_value, *max);
404                         *max = MAX(current->value + current->control_out_value, *max);
405                 }
406         }
407
408 // Test joining regions
409         FloatAuto *prev = 0;
410         FloatAuto *next = 0;
411         int64_t unit_step = edl->local_session->zoom_sample;
412         if(track->data_type == TRACK_VIDEO)
413                 unit_step = (int64_t)(unit_step * 
414                         edl->session->frame_rate / 
415                         edl->session->sample_rate);
416         unit_step = MAX(unit_step, 1);
417         for(int64_t position = unit_start; 
418                 position < unit_end; 
419                 position += unit_step)
420         {
421                 float value = get_value(position,
422                         PLAY_FORWARD,
423                         prev,
424                         next);
425                 if(*coords_undefined)
426                 {
427                         *min = *max = value;
428                         *coords_undefined = 0;
429                 }
430                 else
431                 {
432                         *min = MIN(value, *min);
433                         *max = MAX(value, *max);
434                 }       
435         }
436 }
437
438 void FloatAutos::dump()
439 {
440         printf("        FloatAutos::dump %p\n", this);
441         printf("        Default: position " _LD " value=%f\n", 
442                 default_auto->position,
443                 ((FloatAuto*)default_auto)->value);
444         for(Auto* current = first; current; current = NEXT)
445         {
446                 printf("        position " _LD " mode=%d value=%f invalue=%f outvalue=%f\n", 
447                         current->position, 
448                         (int)((FloatAuto*)current)->mode,
449                         ((FloatAuto*)current)->value,
450                         ((FloatAuto*)current)->control_in_value,
451                         ((FloatAuto*)current)->control_out_value);
452 //                      ((FloatAuto*)current)->control_in_position,
453 //                      ((FloatAuto*)current)->control_out_position);
454         }
455 }