r125: This commit was manufactured by cvs2svn to create tag 'r1_1_7-last'.
[cinelerra_cv/mob.git] / hvirtual / cinelerra / bezierautos.C
blobfc9566b7965bbf504fea67200e81596409206161
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()
43 int BezierAutos::paste_derived(FileXML *xml, int64_t start)
45         int64_t frame = xml->tag.get_property("FRAME", 0);
46         BezierAuto* current = (BezierAuto*)add_auto(frame + start, 0, 0, 1);
47         current->load(xml);
48         current->position += start;   // fix the position loaded by load()
51 int BezierAutos::draw(BC_SubWindow *canvas, 
52                                 int pixel, 
53                                 int zoom_track, 
54                                 float units_per_pixel, 
55                                 float view_start, 
56                                 int vertical)
58         return 0;
61 int BezierAutos::get_auto_pixel(int64_t position, float view_start, float units_per_pixel, int frame_half)
63         int result;
65         result = (int)((position - view_start) / units_per_pixel) + frame_half;
67         return result;
70 int64_t BezierAutos::get_auto_frame(int position, float view_start, float units_per_pixel, int frame_half)
72         int64_t result;
74         result = (int64_t)((position) * units_per_pixel + view_start);
76         return result;
79 int BezierAutos::get_frame_half(float scale, int vertical, float units_per_pixel)
81         int result = (int)(.5 * scale * (vertical ? frame_h : frame_w));
82         if(1 / units_per_pixel / 2 < result) result = (int)(1 / units_per_pixel / 2);
83         return result;
86 int BezierAutos::get_center(float &x, 
87                         float &y, 
88                         float &z, 
89                         float frame, 
90                         int direction, 
91                         BezierAuto **before, 
92                         BezierAuto **after)
94         frame = (direction == PLAY_FORWARD) ? frame : (frame - 1);
95         get_neighbors((int64_t)frame, (int64_t)frame, (Auto**)before, (Auto**)after);
97 //printf("BezierAutos::get_center %p %p\n", *before, *after);
98         if(*before == 0 && *after == 0)
99         {
100                 x = ((BezierAuto*)default_auto)->center_x;
101                 y = ((BezierAuto*)default_auto)->center_y;
102                 z = ((BezierAuto*)default_auto)->center_z;
103 //printf("BezierAutos::get_center %f %f %f\n", x, y, z);
104                 return 0;
105         }
107         float x0, x1, x2, x3;
108         float y0, y1, y2, y3;
109         float z0, z1, z2, z3;
110         float frame0, frame1;
112         if(*before)
113         {
114                 x0 = (*before)->center_x;
115                 y0 = (*before)->center_y;
116                 z0 = (*before)->center_z;
117 // printf("BezierAutos::get_center 1 %f %f %f\n", 
118 //      x0,
119 //      y0,
120 //      z0);
121                 frame0 = (float)(*before)->position;
123                 if(*after == 0 || frame == frame0)
124                 {
125                         x = x0;
126                         y = y0;
127                         z = z0;
128                         return 0;
129                 }
131                 x1 = (*before)->control_out_x + x0;
132                 y1 = (*before)->control_out_y + y0;
133                 z1 = (*before)->control_out_z + z0;
134         }
136         if(*after)
137         {
138                 x3 = (*after)->center_x;
139                 y3 = (*after)->center_y;
140                 z3 = (*after)->center_z;
141 // printf("BezierAutos::get_center 2 %f %f %f\n", 
142 //      x3,
143 //      y3,
144 //      z3);
145                 frame1 = (float)(*after)->position;
147                 if(*before == 0 || frame == frame1)
148                 {
149                         x = x3;
150                         y = y3;
151                         z = z3;
152                         return 0;
153                 }
155                 x2 = (*after)->control_in_x + x3;
156                 y2 = (*after)->control_in_y + y3;
157                 z2 = (*after)->control_in_z + z3;
158         }
160         float t = (frame - frame0) / (frame1 - frame0);
161         float tpow2 = t * t;
162         float tpow3 = t * t * t;
163         float invt = 1 - t;
164         float invtpow2 = invt * invt;
165         float invtpow3 = invt * invt * invt;
167         x = (             invtpow3 * x0
168                 + 3 * t     * invtpow2 * x1
169                 + 3 * tpow2 * invt     * x2 
170                 +     tpow3            * x3);
172         y = (             invtpow3 * y0 
173                 + 3 * t     * invtpow2 * y1
174                 + 3 * tpow2 * invt     * y2 
175                 +     tpow3            * y3);
177 // Z is defined as linear for now to simplify the user interface
178         z = t * (z3 - z0) + z0;
180 //      z = (             invtpow3 * z0 
181 //              + 3 * t     * invtpow2 * z1
182 //              + 3 * tpow2 * invt     * z2 
183 //              +     tpow3            * z3);
187 // printf("BezierAutos::get_center 3 %d %f %f %f\n", 
188 //      (int64_t)frame,
189 //      x,
190 //      y,
191 //      z);
192         return 0;
195 int BezierAutos::swap_out_selected()
197         if(selected)
198         {
199                 BezierAuto *bezier_selected = (BezierAuto*)selected;
200                 new_selected->position = bezier_selected->position;
201                 new_selected->center_x = bezier_selected->center_x;
202                 new_selected->control_in_x = bezier_selected->control_in_x;
203                 new_selected->control_out_x = bezier_selected->control_out_x;
204                 new_selected->center_y = bezier_selected->center_y;
205                 new_selected->control_in_y = bezier_selected->control_in_y;
206                 new_selected->control_out_y = bezier_selected->control_out_y;
207                 new_selected->center_z = bezier_selected->center_z;
208                 new_selected->control_in_z = bezier_selected->control_in_z;
209                 new_selected->control_out_z = bezier_selected->control_out_z;
211                 bezier_selected->position = old_selected->position;
212                 bezier_selected->center_x = old_selected->center_x;
213                 bezier_selected->control_in_x = old_selected->control_in_x;
214                 bezier_selected->control_out_x = old_selected->control_out_x;
215                 bezier_selected->center_y = old_selected->center_y;
216                 bezier_selected->control_in_y = old_selected->control_in_y;
217                 bezier_selected->control_out_y = old_selected->control_out_y;
218                 bezier_selected->center_z = old_selected->center_z;
219                 bezier_selected->control_in_z = old_selected->control_in_z;
220                 bezier_selected->control_out_z = old_selected->control_out_z;
221         }
224 int BezierAutos::swap_in_selected()
226         if(selected)
227         {
228                 BezierAuto *bezier_selected = (BezierAuto*)selected;
229                 bezier_selected->position = new_selected->position;
230                 bezier_selected->center_x = new_selected->center_x;
231                 bezier_selected->control_in_x = new_selected->control_in_x;
232                 bezier_selected->control_out_x = new_selected->control_out_x;
233                 bezier_selected->center_y = new_selected->center_y;
234                 bezier_selected->control_in_y = new_selected->control_in_y;
235                 bezier_selected->control_out_y = new_selected->control_out_y;
236                 bezier_selected->center_z = new_selected->center_z;
237                 bezier_selected->control_in_z = new_selected->control_in_z;
238                 bezier_selected->control_out_z = new_selected->control_out_z;
239         }
242 int BezierAutos::draw_floating_autos(BC_SubWindow *canvas, 
243                                                 int pixel, 
244                                                 int zoom_track, 
245                                                 float units_per_pixel, 
246                                                 float view_start, 
247                                                 int vertical, 
248                                                 int flash)
250         if(selected) 
251         {
252                 BezierAuto *before = 0, *after = 0;
253                 float frame1, frame2, frame;
254                 int center_pixel;
255                 float view_end;
256                 float scale;
257                 int x, x1, y1, x2, y2;
258                 int skip;
260                 skip = selected->skip;
261                 selected->skip = 0;
263                 center_pixel = pixel + zoom_track / 2;
264                 view_end = view_start + units_per_pixel * (vertical ? canvas->get_h() : canvas->get_w());
265                 scale = (float)zoom_track / (vertical ? frame_w : frame_h);
267                 before = (BezierAuto*)selected->previous;
268                 after = (BezierAuto*)selected->next;
269                 
270                 frame1 = before ? before->position : view_start;
271                 frame2 = after ? after->position : view_end;
272                 if(frame1 < view_start) frame1 = view_start;
273                 if(frame2 > view_end) frame2 = view_end;
274                 x = get_auto_pixel((int64_t)frame1, view_start, units_per_pixel, get_frame_half(scale, vertical, units_per_pixel));
275                 before = 0;
276                 after = 0;
278                 canvas->set_inverse();
279                 canvas->set_color(WHITE);
281 // skip drawing line for now
282 //              get_center(x1, y1, z1, frame1 - units_per_pixel, 0, &before, &after);
283 //              if(vertical)
284 //              {
285 //                      x1 = (int)(x1 * scale + center_pixel);
286 //              }
287 //              else
288 //              {
289 //                      y1 = (int)(y1 * scale + center_pixel);
290 //              }
291 //              
292 //              for(frame = frame1; frame < frame2; frame += units_per_pixel, x++)
293 //              {
294 //                      get_center(x2, y2, z2, frame, 0, &before, &after);
295 // 
296 //                      if(vertical)
297 //                      {
298 //                              x2 = (int)(x2 * scale + center_pixel);
299 //                              canvas->draw_line(x1, x - 1, x2, x);
300 //                      }
301 //                      else
302 //                      {
303 //                              y2 = (int)(y2 * scale + center_pixel);
304 //                              canvas->draw_line(y1, x - 1, y2, x);
305 //                      }
306 // 
307 //                      x1 = x2;
308 //                      y1 = y2;
309 //              }
311                 x = get_auto_pixel(selected->position, view_start, units_per_pixel, get_frame_half(scale, vertical, units_per_pixel));
312                 
313                 ((BezierAuto*)selected)->draw(canvas, x, center_pixel, scale, vertical, 1);
314         
315                 canvas->set_opaque();           
316                 selected->skip = skip;
317         
318                 if(flash) 
319                 {
320                         if(vertical)
321                         canvas->flash(pixel, 0, zoom_track, canvas->get_h());
322                         else
323                         canvas->flash(0, pixel, canvas->get_w(), zoom_track);
324                 }
325         }
326         return 0;
329 int BezierAutos::select_auto(BC_SubWindow *canvas, 
330                                                 int pixel, 
331                                                 int zoom_track, 
332                                                 float units_per_pixel, 
333                                                 float view_start, 
334                                                 int cursor_x, 
335                                                 int cursor_y, 
336                                                 int shift_down,
337                                                 int ctrl_down,
338                                                 int mouse_button,
339                                                 int vertical)
341 // cursor_x is relative to frame number
342         BezierAuto *before = 0, *after = 0;
343         int center_pixel;
344         float view_end;
345         float scale;
346         float frame;
347         float x, y, miny, maxy;
348         BezierAuto* current;
350         selection_type = 0;
351         center_pixel = pixel + zoom_track / 2;
352         view_end = view_start + units_per_pixel * (vertical ? canvas->get_h() : canvas->get_w());
353         scale = (float)zoom_track / (vertical ? frame_w : frame_h);
355         frame = get_auto_frame(cursor_x, view_start, units_per_pixel, vertical);
357 // test autos for selection
358         current = (BezierAuto*)autoof((int64_t)view_start);
359         while(current && current->position <= view_end && !selection_type)
360         {
361                 x = get_auto_pixel(current->position, view_start, units_per_pixel, get_frame_half(scale, vertical, units_per_pixel));
363                 selection_type = ((BezierAuto*)current)->select(canvas, 
364                                                                                 (int64_t)x, 
365                                                                                 center_pixel, 
366                                                                                 scale, 
367                                                                                 cursor_x, 
368                                                                                 cursor_y, 
369                                                                                 shift_down, 
370                                                                                 ctrl_down, 
371                                                                                 mouse_button, 
372                                                                                 vertical);
374                 if(selection_type)
375                 {
376                         selected = current;
377                         current->skip = 1;
378                 }
379                 current = (BezierAuto*)NEXT;
380         }
382 // test line for selection
383         if(!selection_type && !shift_down)
384         {
385 // don't use auto line for now
386 //              get_center(x, y, frame, 0, &before, &after);
388 //              if(vertical) y = x;
390 //              miny = (int)(y * scale + center_pixel - 5);
391 //              maxy = miny + 10;
393                 miny = center_pixel - 5;
394                 maxy = center_pixel + 5;
396                 if(cursor_y > miny && cursor_y < maxy)
397                 {
398                         selected = add_auto((int64_t)frame, center_x, center_y, center_z);
400 // copy values from neighbor if possible
401                         BezierAuto *neighbor = 0, *bezier_selected = (BezierAuto*)selected;
402                         if(selected->previous)
403                         {
404                                 neighbor = (BezierAuto*)selected->previous;
405                         }
406                         else
407                         if(selected->next)
408                         {
409                                 neighbor = (BezierAuto*)selected->next;
410                         }
411                         
412                         if(neighbor)
413                         {
414 // center point should be copied.
415 // Control points should be zero.
416                                 bezier_selected->center_x = neighbor->center_x;
417                                 bezier_selected->center_y = neighbor->center_y;
418                                 bezier_selected->center_z = neighbor->center_z;
419 //                              bezier_selected->control_in_x = neighbor->control_in_x;
420 //                              bezier_selected->control_in_y = neighbor->control_in_y;
421 //                              bezier_selected->control_in_z = neighbor->control_in_z;
422 //                              bezier_selected->control_out_x = neighbor->control_out_x;
423 //                              bezier_selected->control_out_y = neighbor->control_out_y;
424 //                              bezier_selected->control_out_z = neighbor->control_out_z;
425                         }
427 // default to sample selection
428                         selection_type = 1;
429                         selected->skip = 1;
430                 }
431         }
433         if(selection_type)
434         {
435                 draw_floating_autos(canvas, 
436                                                 pixel, 
437                                                 zoom_track, 
438                                                 units_per_pixel, 
439                                                 view_start, 
440                                                 vertical, 
441                                                 1);
443                 get_virtual_center(virtual_center_x, virtual_center_y, cursor_x, cursor_y, vertical, scale);
444         }
446         return selection_type;
449 int BezierAutos::get_virtual_center(float &x, float &y, int cursor_x, int cursor_y, int vertical, float scale)
451 // get virtual center relative to track canvas
452         if(selected)
453         {
454                 BezierAuto *current = (BezierAuto*)selected;
455                 float selected_x = 0;
456                 float selected_y = 0;
457                 switch(selection_type)
458                 {
459                         case 2:
460                                 selected_x = current->center_x;
461                                 selected_y = current->center_y;
462                                 break;
463                         case 3:
464                                 selected_x = 0;
465                                 selected_y = current->center_z * virtual_h;
466                                 break;
467                         case 4:
468                                 selected_x = current->control_in_x;
469                                 selected_y = current->control_in_y;
470                                 break;
471                         case 5:
472                                 selected_x = current->control_out_x;
473                                 selected_y = current->control_out_y;
474                                 break;
475                         case 6:
476                                 selected_x = 0;
477                                 selected_y = current->control_in_z * virtual_h;
478                                 break;
479                         case 7:
480                                 selected_x = 0;
481                                 selected_y = current->control_out_z * virtual_h;
482                                 break;
483                         default:
484                                 selected_x = 0;
485                                 selected_y = 0;
486                                 break;
487                 }
489 // control points are independant of vertical tracks
490                 if(vertical)
491                 {
492                         cursor_x ^= cursor_y;
493                         cursor_y ^= cursor_x;
494                         cursor_x ^= cursor_y;
495                 }
497                 if(frame_w) 
498                         x = center_x + cursor_x - selected_x;
499                 else 
500                         x = cursor_x;
502                 y = center_y + cursor_y - selected_y;
503         }
506 int BezierAutos::move_auto(BC_SubWindow *canvas, 
507                                         int pixel, 
508                                         int zoom_track, 
509                                         float units_per_pixel, 
510                                         float view_start, 
511                                         int cursor_x, 
512                                         int cursor_y, 
513                                         int shift_down, 
514                                         int vertical)
516         int result = 0;
517         if(selected)
518         {
519                 BezierAuto* current = (BezierAuto*)selected;
520                 int64_t position;
521                 float scale = (float)zoom_track / (vertical ? frame_w : frame_h);
522 // Frame auto is on.
523                 position = get_auto_frame(cursor_x, view_start, units_per_pixel, vertical);
524                 if(position < 0) position = 0;
526                 if(selection_type == 1)
527                 {
528 // move frame
529                         if(position != current->position) result = 1;
530                         current->position = position;
531                 }
532                 else
533                 {
534 // move control
535 // relative to frame
536                         float real_x;
537                         if(frame_w) 
538                                 real_x = (float)((vertical ? cursor_y : cursor_x) - virtual_center_x);
539                         else
540                                 real_x = 0;
541                         
542                         float real_y = (float)((vertical ? cursor_x : cursor_y) - virtual_center_y);
544                         switch(selection_type)
545                         {
546                                 case 2:
547                                         current->center_x = real_x;
548                                         current->center_y = real_y;
549                                         break;
550                                 case 3:
551                                         current->center_z = real_y / virtual_h;
552                                         break;
553                                 case 4:
554                                         current->control_in_x = real_x;
555                                         current->control_in_y = real_y;
556                                         break;
557                                 case 5:
558                                         current->control_out_x = real_x;
559                                         current->control_out_y = real_y;
560                                         break;
561                                 case 6:
562                                         current->control_in_z = real_y / virtual_h;
563                                         break;
564                                 case 7:
565                                         current->control_out_z = real_y / virtual_h;
566                                         break;
567                         }
568                         result = 1;
569                 }
570         }
571         return result;
574 int BezierAutos::release_auto_derived()
576         selection_type = 0;
580 Auto* BezierAutos::add_auto(int64_t frame, float x, float y, float z)
582         BezierAuto* current = (BezierAuto*)autoof(frame);
583         BezierAuto* new_auto;
584         
585         insert_before(current, new_auto = new BezierAuto(edl, this));
586         new_auto->position = frame;
587         new_auto->control_in_x = new_auto->control_out_x = 0;
588         new_auto->control_in_y = new_auto->control_out_y = 0;
589         new_auto->control_in_z = new_auto->control_out_z = 0;
590         new_auto->center_x = x;
591         new_auto->center_y = y;
592         new_auto->center_z = z;
594 //printf("BezierAutos::add_auto %lld\n", new_auto->position);
595         return (Auto*)new_auto;
598 Auto* BezierAutos::append_auto()
600         return append(new BezierAuto(edl, this));
603 int BezierAutos::scale_video(float scale, int *offsets)
605         for(BezierAuto *current = (BezierAuto*)first; 
606         current; 
607         current = (BezierAuto*)NEXT)
608         {
609                 current->center_x -= offsets[0];
610                 current->center_y -= offsets[1];
611                 current->center_z *= scale;
612         }
613         return 0;
616 int BezierAutos::dump()
618         printf("        BezierAutos::dump %p\n", this);
619         printf("        Default: position %lld x %f y %f z %f\n", 
620                 default_auto->position, 
621                 ((BezierAuto*)default_auto)->center_x,
622                 ((BezierAuto*)default_auto)->center_y,
623                 ((BezierAuto*)default_auto)->center_z);
624         for(Auto* current = first; current; current = NEXT)
625         {
626                 printf("        position %lld x %f y %f z %f\n", 
627                         current->position, 
628                         ((BezierAuto*)current)->center_x,
629                         ((BezierAuto*)current)->center_y,
630                         ((BezierAuto*)current)->center_z);
631         }
632         return 0;