r602: Fix baver's code... don't insert timecode when show_tc is not set
[cinelerra_cv/mob.git] / cinelerra / bezierautos.C
blobb1c1c4b9db10e6f9850ae11f63938cf901fb2e4d
1 #include "bezierauto.h"
2 #include "bezierautos.h"
3 #include "filexml.h"
4 #include "maskautos.h"
5 #include "mwindow.h"
6 #include "transportque.inc"
9 BezierAutos::BezierAutos(EDL *edl, 
10                         Track *track, 
11                         int color, 
12                         float center_x,
13                         float center_y, 
14                         float center_z, 
15                         float frame_w,
16                         float frame_h,
17                         float virtual_w,
18                         float virtual_h)
19  : Autos(edl, track)
21         old_selected = new BezierAuto(edl, 0);
22         new_selected = new BezierAuto(edl, 0);
23         this->center_x = center_x;
24         this->center_y = center_y;
25         this->center_z = center_z;
26         this->virtual_w = virtual_w;
27         this->virtual_h = virtual_h;
28         virtual_center_x = 0;
29         virtual_center_y = 0;
30         selection_type = 0;
34 Auto* BezierAutos::new_auto()
36         return new BezierAuto(edl, this);
39 BezierAutos::~BezierAutos()
41         delete old_selected;
42         delete new_selected;
45 int BezierAutos::paste_derived(FileXML *xml, int64_t start)
47         int64_t frame = xml->tag.get_property("FRAME", 0);
48         BezierAuto* current = (BezierAuto*)add_auto(frame + start, 0, 0, 1);
49         current->load(xml);
50         current->position += start;   // fix the position loaded by load()
53 int BezierAutos::draw(BC_SubWindow *canvas, 
54                                 int pixel, 
55                                 int zoom_track, 
56                                 float units_per_pixel, 
57                                 float view_start, 
58                                 int vertical)
60         return 0;
63 int BezierAutos::get_auto_pixel(int64_t position, float view_start, float units_per_pixel, int frame_half)
65         int result;
67         result = (int)((position - view_start) / units_per_pixel) + frame_half;
69         return result;
72 int64_t BezierAutos::get_auto_frame(int position, float view_start, float units_per_pixel, int frame_half)
74         int64_t result;
76         result = (int64_t)((position) * units_per_pixel + view_start);
78         return result;
81 int BezierAutos::get_frame_half(float scale, int vertical, float units_per_pixel)
83         int result = (int)(.5 * scale * (vertical ? frame_h : frame_w));
84         if(1 / units_per_pixel / 2 < result) result = (int)(1 / units_per_pixel / 2);
85         return result;
88 int BezierAutos::get_center(float &x, 
89                         float &y, 
90                         float &z, 
91                         int64_t frame, 
92                         int direction, 
93                         BezierAuto **before, 
94                         BezierAuto **after)
96         frame = (direction == PLAY_FORWARD) ? frame : (frame - 1);
97         get_neighbors(frame, frame, (Auto**)before, (Auto**)after);
99 // printf("BezierAutos::get_center %lld %p %p\n", frame, *before, *after);
100 // printf("BezierAutos::get_center %lld %lld\n", 
101 // *before ? (*before)->position : -1, 
102 // *after ? (*after)->position : -1);
103         if(*before == 0 && *after == 0)
104         {
105                 x = ((BezierAuto*)default_auto)->center_x;
106                 y = ((BezierAuto*)default_auto)->center_y;
107                 z = ((BezierAuto*)default_auto)->center_z;
108 //printf("BezierAutos::get_center %f %f %f\n", x, y, z);
109                 return 0;
110         }
111         else
112         if(*before == *after)
113         {
114                 x = ((BezierAuto*)*before)->center_x;
115                 y = ((BezierAuto*)*before)->center_y;
116                 z = ((BezierAuto*)*before)->center_z;
117 //printf("BezierAutos::get_center %lld %lld %f %f %f\n", 
118 //frame, (*before)->position, x, y, z);
119                 return 0;
120         }
122         float x0, x1, x2, x3;
123         float y0, y1, y2, y3;
124         float z0, z1, z2, z3;
125         float frame0, frame1;
127         if(*before)
128         {
129                 x0 = (*before)->center_x;
130                 y0 = (*before)->center_y;
131                 z0 = (*before)->center_z;
132 // printf("BezierAutos::get_center 1 %f %f %f\n", 
133 //      x0,
134 //      y0,
135 //      z0);
136                 frame0 = (float)(*before)->position;
138                 if(*after == 0 || frame == frame0)
139                 {
140                         x = x0;
141                         y = y0;
142                         z = z0;
143                         return 0;
144                 }
146                 x1 = (*before)->control_out_x + x0;
147                 y1 = (*before)->control_out_y + y0;
148                 z1 = (*before)->control_out_z + z0;
149         }
151         if(*after)
152         {
153                 x3 = (*after)->center_x;
154                 y3 = (*after)->center_y;
155                 z3 = (*after)->center_z;
156 // printf("BezierAutos::get_center 2 %f %f %f\n", 
157 //      x3,
158 //      y3,
159 //      z3);
160                 frame1 = (float)(*after)->position;
162                 if(*before == 0 || frame == frame1)
163                 {
164                         x = x3;
165                         y = y3;
166                         z = z3;
167                         return 0;
168                 }
170                 x2 = (*after)->control_in_x + x3;
171                 y2 = (*after)->control_in_y + y3;
172                 z2 = (*after)->control_in_z + z3;
173         }
175         float t = (frame - frame0) / (frame1 - frame0);
176         float tpow2 = t * t;
177         float tpow3 = t * t * t;
178         float invt = 1 - t;
179         float invtpow2 = invt * invt;
180         float invtpow3 = invt * invt * invt;
182         x = (             invtpow3 * x0
183                 + 3 * t     * invtpow2 * x1
184                 + 3 * tpow2 * invt     * x2 
185                 +     tpow3            * x3);
187         y = (             invtpow3 * y0 
188                 + 3 * t     * invtpow2 * y1
189                 + 3 * tpow2 * invt     * y2 
190                 +     tpow3            * y3);
192 // Z is defined as linear for now to simplify the user interface
193         z = t * (z3 - z0) + z0;
195 //      z = (             invtpow3 * z0 
196 //              + 3 * t     * invtpow2 * z1
197 //              + 3 * tpow2 * invt     * z2 
198 //              +     tpow3            * z3);
202 // printf("BezierAutos::get_center 3 %d %f %f %f\n", 
203 //      (int64_t)frame,
204 //      x,
205 //      y,
206 //      z);
207         return 0;
210 int BezierAutos::swap_out_selected()
212         if(selected)
213         {
214                 BezierAuto *bezier_selected = (BezierAuto*)selected;
215                 new_selected->position = bezier_selected->position;
216                 new_selected->center_x = bezier_selected->center_x;
217                 new_selected->control_in_x = bezier_selected->control_in_x;
218                 new_selected->control_out_x = bezier_selected->control_out_x;
219                 new_selected->center_y = bezier_selected->center_y;
220                 new_selected->control_in_y = bezier_selected->control_in_y;
221                 new_selected->control_out_y = bezier_selected->control_out_y;
222                 new_selected->center_z = bezier_selected->center_z;
223                 new_selected->control_in_z = bezier_selected->control_in_z;
224                 new_selected->control_out_z = bezier_selected->control_out_z;
226                 bezier_selected->position = old_selected->position;
227                 bezier_selected->center_x = old_selected->center_x;
228                 bezier_selected->control_in_x = old_selected->control_in_x;
229                 bezier_selected->control_out_x = old_selected->control_out_x;
230                 bezier_selected->center_y = old_selected->center_y;
231                 bezier_selected->control_in_y = old_selected->control_in_y;
232                 bezier_selected->control_out_y = old_selected->control_out_y;
233                 bezier_selected->center_z = old_selected->center_z;
234                 bezier_selected->control_in_z = old_selected->control_in_z;
235                 bezier_selected->control_out_z = old_selected->control_out_z;
236         }
239 int BezierAutos::swap_in_selected()
241         if(selected)
242         {
243                 BezierAuto *bezier_selected = (BezierAuto*)selected;
244                 bezier_selected->position = new_selected->position;
245                 bezier_selected->center_x = new_selected->center_x;
246                 bezier_selected->control_in_x = new_selected->control_in_x;
247                 bezier_selected->control_out_x = new_selected->control_out_x;
248                 bezier_selected->center_y = new_selected->center_y;
249                 bezier_selected->control_in_y = new_selected->control_in_y;
250                 bezier_selected->control_out_y = new_selected->control_out_y;
251                 bezier_selected->center_z = new_selected->center_z;
252                 bezier_selected->control_in_z = new_selected->control_in_z;
253                 bezier_selected->control_out_z = new_selected->control_out_z;
254         }
257 int BezierAutos::draw_floating_autos(BC_SubWindow *canvas, 
258                                                 int pixel, 
259                                                 int zoom_track, 
260                                                 float units_per_pixel, 
261                                                 float view_start, 
262                                                 int vertical, 
263                                                 int flash)
265         if(selected) 
266         {
267                 BezierAuto *before = 0, *after = 0;
268                 float frame1, frame2, frame;
269                 int center_pixel;
270                 float view_end;
271                 float scale;
272                 int x, x1, y1, x2, y2;
273                 int skip;
275                 skip = selected->skip;
276                 selected->skip = 0;
278                 center_pixel = pixel + zoom_track / 2;
279                 view_end = view_start + units_per_pixel * (vertical ? canvas->get_h() : canvas->get_w());
280                 scale = (float)zoom_track / (vertical ? frame_w : frame_h);
282                 before = (BezierAuto*)selected->previous;
283                 after = (BezierAuto*)selected->next;
284                 
285                 frame1 = before ? before->position : view_start;
286                 frame2 = after ? after->position : view_end;
287                 if(frame1 < view_start) frame1 = view_start;
288                 if(frame2 > view_end) frame2 = view_end;
289                 x = get_auto_pixel((int64_t)frame1, view_start, units_per_pixel, get_frame_half(scale, vertical, units_per_pixel));
290                 before = 0;
291                 after = 0;
293                 canvas->set_inverse();
294                 canvas->set_color(WHITE);
296 // skip drawing line for now
297 //              get_center(x1, y1, z1, frame1 - units_per_pixel, 0, &before, &after);
298 //              if(vertical)
299 //              {
300 //                      x1 = (int)(x1 * scale + center_pixel);
301 //              }
302 //              else
303 //              {
304 //                      y1 = (int)(y1 * scale + center_pixel);
305 //              }
306 //              
307 //              for(frame = frame1; frame < frame2; frame += units_per_pixel, x++)
308 //              {
309 //                      get_center(x2, y2, z2, frame, 0, &before, &after);
310 // 
311 //                      if(vertical)
312 //                      {
313 //                              x2 = (int)(x2 * scale + center_pixel);
314 //                              canvas->draw_line(x1, x - 1, x2, x);
315 //                      }
316 //                      else
317 //                      {
318 //                              y2 = (int)(y2 * scale + center_pixel);
319 //                              canvas->draw_line(y1, x - 1, y2, x);
320 //                      }
321 // 
322 //                      x1 = x2;
323 //                      y1 = y2;
324 //              }
326                 x = get_auto_pixel(selected->position, view_start, units_per_pixel, get_frame_half(scale, vertical, units_per_pixel));
327                 
328                 ((BezierAuto*)selected)->draw(canvas, x, center_pixel, scale, vertical, 1);
329         
330                 canvas->set_opaque();           
331                 selected->skip = skip;
332         
333                 if(flash) 
334                 {
335                         if(vertical)
336                         canvas->flash(pixel, 0, zoom_track, canvas->get_h());
337                         else
338                         canvas->flash(0, pixel, canvas->get_w(), zoom_track);
339                 }
340         }
341         return 0;
344 int BezierAutos::select_auto(BC_SubWindow *canvas, 
345                                                 int pixel, 
346                                                 int zoom_track, 
347                                                 float units_per_pixel, 
348                                                 float view_start, 
349                                                 int cursor_x, 
350                                                 int cursor_y, 
351                                                 int shift_down,
352                                                 int ctrl_down,
353                                                 int mouse_button,
354                                                 int vertical)
356 // cursor_x is relative to frame number
357         BezierAuto *before = 0, *after = 0;
358         int center_pixel;
359         float view_end;
360         float scale;
361         float frame;
362         float x, y, miny, maxy;
363         BezierAuto* current;
365         selection_type = 0;
366         center_pixel = pixel + zoom_track / 2;
367         view_end = view_start + units_per_pixel * (vertical ? canvas->get_h() : canvas->get_w());
368         scale = (float)zoom_track / (vertical ? frame_w : frame_h);
370         frame = get_auto_frame(cursor_x, view_start, units_per_pixel, vertical);
372 // test autos for selection
373         current = (BezierAuto*)autoof((int64_t)view_start);
374         while(current && current->position <= view_end && !selection_type)
375         {
376                 x = get_auto_pixel(current->position, view_start, units_per_pixel, get_frame_half(scale, vertical, units_per_pixel));
378                 selection_type = ((BezierAuto*)current)->select(canvas, 
379                                                                                 (int64_t)x, 
380                                                                                 center_pixel, 
381                                                                                 scale, 
382                                                                                 cursor_x, 
383                                                                                 cursor_y, 
384                                                                                 shift_down, 
385                                                                                 ctrl_down, 
386                                                                                 mouse_button, 
387                                                                                 vertical);
389                 if(selection_type)
390                 {
391                         selected = current;
392                         current->skip = 1;
393                 }
394                 current = (BezierAuto*)NEXT;
395         }
397 // test line for selection
398         if(!selection_type && !shift_down)
399         {
400 // don't use auto line for now
401 //              get_center(x, y, frame, 0, &before, &after);
403 //              if(vertical) y = x;
405 //              miny = (int)(y * scale + center_pixel - 5);
406 //              maxy = miny + 10;
408                 miny = center_pixel - 5;
409                 maxy = center_pixel + 5;
411                 if(cursor_y > miny && cursor_y < maxy)
412                 {
413                         selected = add_auto((int64_t)frame, center_x, center_y, center_z);
415 // copy values from neighbor if possible
416                         BezierAuto *neighbor = 0, *bezier_selected = (BezierAuto*)selected;
417                         if(selected->previous)
418                         {
419                                 neighbor = (BezierAuto*)selected->previous;
420                         }
421                         else
422                         if(selected->next)
423                         {
424                                 neighbor = (BezierAuto*)selected->next;
425                         }
426                         
427                         if(neighbor)
428                         {
429 // center point should be copied.
430 // Control points should be zero.
431                                 bezier_selected->center_x = neighbor->center_x;
432                                 bezier_selected->center_y = neighbor->center_y;
433                                 bezier_selected->center_z = neighbor->center_z;
434 //                              bezier_selected->control_in_x = neighbor->control_in_x;
435 //                              bezier_selected->control_in_y = neighbor->control_in_y;
436 //                              bezier_selected->control_in_z = neighbor->control_in_z;
437 //                              bezier_selected->control_out_x = neighbor->control_out_x;
438 //                              bezier_selected->control_out_y = neighbor->control_out_y;
439 //                              bezier_selected->control_out_z = neighbor->control_out_z;
440                         }
442 // default to sample selection
443                         selection_type = 1;
444                         selected->skip = 1;
445                 }
446         }
448         if(selection_type)
449         {
450                 draw_floating_autos(canvas, 
451                                                 pixel, 
452                                                 zoom_track, 
453                                                 units_per_pixel, 
454                                                 view_start, 
455                                                 vertical, 
456                                                 1);
458                 get_virtual_center(virtual_center_x, virtual_center_y, cursor_x, cursor_y, vertical, scale);
459         }
461         return selection_type;
464 int BezierAutos::get_virtual_center(float &x, float &y, int cursor_x, int cursor_y, int vertical, float scale)
466 // get virtual center relative to track canvas
467         if(selected)
468         {
469                 BezierAuto *current = (BezierAuto*)selected;
470                 float selected_x = 0;
471                 float selected_y = 0;
472                 switch(selection_type)
473                 {
474                         case 2:
475                                 selected_x = current->center_x;
476                                 selected_y = current->center_y;
477                                 break;
478                         case 3:
479                                 selected_x = 0;
480                                 selected_y = current->center_z * virtual_h;
481                                 break;
482                         case 4:
483                                 selected_x = current->control_in_x;
484                                 selected_y = current->control_in_y;
485                                 break;
486                         case 5:
487                                 selected_x = current->control_out_x;
488                                 selected_y = current->control_out_y;
489                                 break;
490                         case 6:
491                                 selected_x = 0;
492                                 selected_y = current->control_in_z * virtual_h;
493                                 break;
494                         case 7:
495                                 selected_x = 0;
496                                 selected_y = current->control_out_z * virtual_h;
497                                 break;
498                         default:
499                                 selected_x = 0;
500                                 selected_y = 0;
501                                 break;
502                 }
504 // control points are independant of vertical tracks
505                 if(vertical)
506                 {
507                         cursor_x ^= cursor_y;
508                         cursor_y ^= cursor_x;
509                         cursor_x ^= cursor_y;
510                 }
512                 if(frame_w) 
513                         x = center_x + cursor_x - selected_x;
514                 else 
515                         x = cursor_x;
517                 y = center_y + cursor_y - selected_y;
518         }
521 int BezierAutos::move_auto(BC_SubWindow *canvas, 
522                                         int pixel, 
523                                         int zoom_track, 
524                                         float units_per_pixel, 
525                                         float view_start, 
526                                         int cursor_x, 
527                                         int cursor_y, 
528                                         int shift_down, 
529                                         int vertical)
531         int result = 0;
532         if(selected)
533         {
534                 BezierAuto* current = (BezierAuto*)selected;
535                 int64_t position;
536                 float scale = (float)zoom_track / (vertical ? frame_w : frame_h);
537 // Frame auto is on.
538                 position = get_auto_frame(cursor_x, view_start, units_per_pixel, vertical);
539                 if(position < 0) position = 0;
541                 if(selection_type == 1)
542                 {
543 // move frame
544                         if(position != current->position) result = 1;
545                         current->position = position;
546                 }
547                 else
548                 {
549 // move control
550 // relative to frame
551                         float real_x;
552                         if(frame_w) 
553                                 real_x = (float)((vertical ? cursor_y : cursor_x) - virtual_center_x);
554                         else
555                                 real_x = 0;
556                         
557                         float real_y = (float)((vertical ? cursor_x : cursor_y) - virtual_center_y);
559                         switch(selection_type)
560                         {
561                                 case 2:
562                                         current->center_x = real_x;
563                                         current->center_y = real_y;
564                                         break;
565                                 case 3:
566                                         current->center_z = real_y / virtual_h;
567                                         break;
568                                 case 4:
569                                         current->control_in_x = real_x;
570                                         current->control_in_y = real_y;
571                                         break;
572                                 case 5:
573                                         current->control_out_x = real_x;
574                                         current->control_out_y = real_y;
575                                         break;
576                                 case 6:
577                                         current->control_in_z = real_y / virtual_h;
578                                         break;
579                                 case 7:
580                                         current->control_out_z = real_y / virtual_h;
581                                         break;
582                         }
583                         result = 1;
584                 }
585         }
586         return result;
589 int BezierAutos::release_auto_derived()
591         selection_type = 0;
595 Auto* BezierAutos::add_auto(int64_t frame, float x, float y, float z)
597         BezierAuto* current = (BezierAuto*)autoof(frame);
598         BezierAuto* new_auto;
599         
600         insert_before(current, new_auto = new BezierAuto(edl, this));
601         new_auto->position = frame;
602         new_auto->control_in_x = new_auto->control_out_x = 0;
603         new_auto->control_in_y = new_auto->control_out_y = 0;
604         new_auto->control_in_z = new_auto->control_out_z = 0;
605         new_auto->center_x = x;
606         new_auto->center_y = y;
607         new_auto->center_z = z;
609 //printf("BezierAutos::add_auto %lld\n", new_auto->position);
610         return (Auto*)new_auto;
613 Auto* BezierAutos::append_auto()
615         return append(new BezierAuto(edl, this));
618 int BezierAutos::scale_video(float scale, int *offsets)
620         for(BezierAuto *current = (BezierAuto*)first; 
621         current; 
622         current = (BezierAuto*)NEXT)
623         {
624                 current->center_x -= offsets[0];
625                 current->center_y -= offsets[1];
626                 current->center_z *= scale;
627         }
628         return 0;
631 int BezierAutos::dump()
633         printf("        BezierAutos::dump %p\n", this);
634         printf("        Default: position %lld x %f y %f z %f\n", 
635                 default_auto->position, 
636                 ((BezierAuto*)default_auto)->center_x,
637                 ((BezierAuto*)default_auto)->center_y,
638                 ((BezierAuto*)default_auto)->center_z);
639         for(Auto* current = first; current; current = NEXT)
640         {
641                 printf("        position %lld x %f y %f z %f\n", 
642                         current->position, 
643                         ((BezierAuto*)current)->center_x,
644                         ((BezierAuto*)current)->center_y,
645                         ((BezierAuto*)current)->center_z);
646         }
647         return 0;