Camera tracking integration
[blender.git] / source / blender / editors / space_clip / tracking_ops.c
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (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 Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2011 Blender Foundation.
21  * All rights reserved.
22  *
23  *
24  * Contributor(s): Blender Foundation,
25  *                 Sergey Sharybin
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 #include "MEM_guardedalloc.h"
31
32 #include "DNA_movieclip_types.h"
33 #include "DNA_object_types.h"   /* SELECT */
34 #include "DNA_scene_types.h"
35 #include "DNA_anim_types.h"
36
37 #include "BLI_utildefines.h"
38 #include "BLI_math.h"
39 #include "BLI_listbase.h"
40 #include "BLI_rect.h"
41 #include "BLI_blenlib.h"
42
43 #include "BKE_main.h"
44 #include "BKE_context.h"
45 #include "BKE_movieclip.h"
46 #include "BKE_tracking.h"
47 #include "BKE_global.h"
48 #include "BKE_animsys.h"
49 #include "BKE_depsgraph.h"
50
51 #include "WM_api.h"
52 #include "WM_types.h"
53
54 #include "ED_screen.h"
55 #include "ED_clip.h"
56 #include "ED_keyframing.h"
57
58 #include "IMB_imbuf_types.h"
59
60 #include "UI_interface.h"
61
62 #include "RNA_access.h"
63 #include "RNA_define.h"
64
65 #include "PIL_time.h"
66
67 #include "UI_view2d.h"
68
69 #include "clip_intern.h"        // own include
70
71 /** \file blender/editors/space_clip/tracking_ops.c
72  *  \ingroup spclip
73  */
74
75 static int space_clip_tracking_poll(bContext *C)
76 {
77         SpaceClip *sc= CTX_wm_space_clip(C);
78
79         if(sc && sc->clip)
80                 return 1;
81
82         return 0;
83 }
84
85 static int space_clip_frame_poll(bContext *C)
86 {
87         SpaceClip *sc= CTX_wm_space_clip(C);
88
89         if(sc) {
90                 MovieClip *clip= ED_space_clip(sc);
91
92                 if(clip)
93                         return BKE_movieclip_has_frame(clip, &sc->user);
94         }
95
96         return 0;
97 }
98
99 /********************** add marker operator *********************/
100
101 static void add_marker(SpaceClip *sc, float x, float y)
102 {
103         MovieClip *clip= ED_space_clip(sc);
104         MovieTrackingTrack *track;
105         MovieTrackingMarker marker;
106         int width, height;
107         float pat[2]= {15.0f, 15.0f}, search[2]= {30.0f, 30.0f}; /* TODO: move to default setting? */
108
109         ED_space_clip_size(sc, &width, &height);
110
111         pat[0] /= (float)width;
112         pat[1] /= (float)height;
113
114         search[0] /= (float)width;
115         search[1] /= (float)height;
116
117         track= MEM_callocN(sizeof(MovieTrackingTrack), "add_marker_exec track");
118
119         marker.pos[0]= x;
120         marker.pos[1]= y;
121         marker.framenr= sc->user.framenr;
122
123         copy_v2_v2(track->pat_max, pat);
124         negate_v2_v2(track->pat_min, pat);
125
126         copy_v2_v2(track->search_max, search);
127         negate_v2_v2(track->search_min, search);
128
129         BKE_tracking_insert_marker(track, &marker);
130
131         BLI_addtail(&clip->tracking.tracks, track);
132
133         BKE_movieclip_select_track(clip, track, TRACK_AREA_ALL, 0);
134         BKE_movieclip_set_selection(clip, MCLIP_SEL_TRACK, track);
135 }
136
137 static int add_marker_exec(bContext *C, wmOperator *op)
138 {
139         SpaceClip *sc= CTX_wm_space_clip(C);
140         MovieClip *clip= ED_space_clip(sc);
141         float pos[2];
142         int width, height;
143
144         ED_space_clip_size(sc, &width, &height);
145         if(!width || !height)
146                 return OPERATOR_CANCELLED;
147
148         RNA_float_get_array(op->ptr, "location", pos);
149
150         add_marker(sc, pos[0], pos[1]);
151
152         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, clip);
153
154         return OPERATOR_FINISHED;
155 }
156
157 static void mouse_pos(bContext *C, wmEvent *event, float co[2])
158 {
159         ARegion *ar= CTX_wm_region(C);
160         SpaceClip *sc= CTX_wm_space_clip(C);
161         int sx, sy;
162
163         UI_view2d_to_region_no_clip(&ar->v2d, 0.0f, 0.0f, &sx, &sy);
164         co[0]= ((float)event->mval[0]-sx)/sc->zoom;
165         co[1]= ((float)event->mval[1]-sy)/sc->zoom;
166 }
167
168 static int add_marker_invoke(bContext *C, wmOperator *op, wmEvent *event)
169 {
170         SpaceClip *sc= CTX_wm_space_clip(C);
171         int width, height;
172         float co[2];
173
174         ED_space_clip_size(sc, &width, &height);
175         if(!width || !height)
176                 return OPERATOR_CANCELLED;
177
178         mouse_pos(C, event, co);
179         co[0]/= width;
180         co[1]/= height;
181
182         RNA_float_set_array(op->ptr, "location", co);
183
184         return add_marker_exec(C, op);
185 }
186
187 void CLIP_OT_add_marker(wmOperatorType *ot)
188 {
189         /* identifiers */
190         ot->name= "Add Marker";
191         ot->idname= "CLIP_OT_add_marker";
192         ot->description= "Place new marker at specified location";
193
194         /* api callbacks */
195         ot->invoke= add_marker_invoke;
196         ot->exec= add_marker_exec;
197         ot->poll= space_clip_tracking_poll;
198
199         /* flags */
200         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
201
202         /* properties */
203         RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MIN, FLT_MAX,
204                 "Location", "Location of marker on frame.", -1.f, 1.f);
205 }
206
207 /********************** delete operator *********************/
208
209 static int delete_exec(bContext *C, wmOperator *UNUSED(op))
210 {
211         SpaceClip *sc= CTX_wm_space_clip(C);
212         MovieClip *clip= ED_space_clip(sc);
213         MovieTrackingTrack *track= clip->tracking.tracks.first, *next;
214
215         while(track) {
216                 next= track->next;
217
218                 if(track->flag&SELECT) {
219                         BKE_tracking_free_track(track);
220                         BLI_freelinkN(&clip->tracking.tracks, track);
221                 }
222
223                 track= next;
224         }
225
226         BKE_movieclip_set_selection(clip, MCLIP_SEL_NONE, NULL);
227         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, clip);
228
229         return OPERATOR_FINISHED;
230 }
231
232 void CLIP_OT_delete(wmOperatorType *ot)
233 {
234         /* identifiers */
235         ot->name= "Delete";
236         ot->idname= "CLIP_OT_delete";
237         ot->description= "Delete selected tracks";
238
239         /* api callbacks */
240         ot->invoke= WM_operator_confirm;
241         ot->exec= delete_exec;
242         ot->poll= space_clip_tracking_poll;
243
244         /* flags */
245         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
246 }
247
248 /********************** mouse select operator *********************/
249
250 static int mouse_on_size(float co[2], float x1, float y1, float x2, float y2, float epsx, float epsy)
251 {
252         if(x1>x2) SWAP(float, x1, x2);
253         if(y1>y2) SWAP(float, y1, y2);
254
255         return (co[0]>=x1-epsx && co[0]<=x2+epsx) && (co[1]>=y1-epsy && co[1]<=y2+epsy);
256 }
257
258 static int mouse_on_rect(float co[2], float pos[2], float min[2], float max[2], float epsx, float epsy)
259 {
260         return mouse_on_size(co, pos[0]+min[0], pos[1]+min[1], pos[0]+max[0], pos[1]+min[1], epsx, epsy) ||
261                mouse_on_size(co, pos[0]+min[0], pos[1]+min[1], pos[0]+min[0], pos[1]+max[1], epsx, epsy) ||
262                mouse_on_size(co, pos[0]+min[0], pos[1]+max[1], pos[0]+max[0], pos[1]+max[1], epsx, epsy) ||
263                mouse_on_size(co, pos[0]+max[0], pos[1]+min[1], pos[0]+max[0], pos[1]+max[1], epsx, epsy);
264 }
265
266 static int track_mouse_area(SpaceClip *sc, float co[2], MovieTrackingTrack *track)
267 {
268         MovieTrackingMarker *marker= BKE_tracking_get_marker(track, sc->user.framenr);
269         float epsx, epsy;
270         int width, height;
271
272         ED_space_clip_size(sc, &width, &height);
273
274         epsx= MIN4(track->pat_min[0]-track->search_min[0], track->search_max[0]-track->pat_max[0],
275                    fabsf(track->pat_min[0]), fabsf(track->pat_max[0])) / 2;
276         epsy= MIN4(track->pat_min[1]-track->search_min[1], track->search_max[1]-track->pat_max[1],
277                    fabsf(track->pat_min[1]), fabsf(track->pat_max[1])) / 2;
278
279         epsx= MAX2(epsy, 2.0 / width);
280         epsy= MAX2(epsy, 2.0 / height);
281
282         if(fabsf(co[0]-marker->pos[0])< epsx && fabsf(co[1]-marker->pos[1])<=epsy)
283                 return TRACK_AREA_POINT;
284
285         if(sc->flag&SC_SHOW_MARKER_PATTERN)
286                 if(mouse_on_rect(co, marker->pos, track->pat_min, track->pat_max, epsx, epsy))
287                         return TRACK_AREA_PAT;
288
289         if(sc->flag&SC_SHOW_MARKER_SEARCH)
290                 if(mouse_on_rect(co, marker->pos, track->search_min, track->search_max, epsx, epsy))
291                         return TRACK_AREA_SEARCH;
292
293         return TRACK_AREA_NONE;
294 }
295
296 static float dist_to_rect(float co[2], float pos[2], float min[2], float max[2])
297 {
298         float d1, d2, d3, d4;
299         float p[2]= {co[0]-pos[0], co[1]-pos[1]};
300         float v1[2]= {min[0], min[1]}, v2[2]= {max[0], min[1]},
301               v3[2]= {max[0], max[1]}, v4[2]= {min[0], max[1]};
302
303         d1= dist_to_line_segment_v2(p, v1, v2);
304         d2= dist_to_line_segment_v2(p, v2, v3);
305         d3= dist_to_line_segment_v2(p, v3, v4);
306         d4= dist_to_line_segment_v2(p, v4, v1);
307
308         return MIN4(d1, d2, d3, d4);
309 }
310
311 static MovieTrackingTrack *find_nearest_track(SpaceClip *sc, MovieClip *clip, float co[2])
312 {
313         MovieTrackingTrack *track= NULL, *cur;
314         float mindist= 0.0f;
315
316         cur= clip->tracking.tracks.first;
317         while(cur) {
318                 MovieTrackingMarker *marker= BKE_tracking_get_marker(cur, sc->user.framenr);
319                 float dist, d1, d2, d3;
320
321                 if(marker) {
322                         d1= sqrtf((co[0]-marker->pos[0])*(co[0]-marker->pos[0])+
323                                           (co[1]-marker->pos[1])*(co[1]-marker->pos[1])); /* distance to marker point */
324                         d2= dist_to_rect(co, marker->pos, cur->pat_min, cur->pat_max); /* distance to search boundbox */
325                         d3= dist_to_rect(co, marker->pos, cur->search_min, cur->search_max); /* distance to search boundbox */
326
327                         /* choose minimal distance. useful for cases of overlapped markers. */
328                         dist= MIN3(d1, d2, d3);
329
330                         if(track==NULL || dist<mindist) {
331                                 track= cur;
332                                 mindist= dist;
333                         }
334                 }
335
336                 cur= cur->next;
337         }
338
339         return track;
340 }
341
342 static int mouse_select(bContext *C, float co[2], int extend)
343 {
344         SpaceClip *sc= CTX_wm_space_clip(C);
345         MovieClip *clip= ED_space_clip(sc);
346         MovieTrackingTrack *track= NULL;        /* selected marker */
347
348         track= find_nearest_track(sc, clip, co);
349
350         if(track) {
351                 int area= track_mouse_area(sc, co, track);
352
353                 if(area==TRACK_AREA_NONE)
354                         return OPERATOR_FINISHED;
355
356                 if(!TRACK_SELECTED(track))
357                         area= TRACK_AREA_ALL;
358
359                 if(extend && TRACK_AREA_SELECTED(track, area)) {
360                         BKE_movieclip_deselect_track(clip, track, area);
361                 } else {
362                         if(area==TRACK_AREA_POINT) area= TRACK_AREA_ALL;
363
364                         BKE_movieclip_select_track(clip, track, area, extend);
365                         BKE_movieclip_set_selection(clip, MCLIP_SEL_TRACK, track);
366                 }
367         }
368
369         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, NULL);
370
371         return OPERATOR_FINISHED;
372 }
373
374 static int select_exec(bContext *C, wmOperator *op)
375 {
376         float co[2];
377         int extend;
378
379         RNA_float_get_array(op->ptr, "location", co);
380         extend= RNA_boolean_get(op->ptr, "extend");
381
382         return mouse_select(C, co, extend);
383 }
384
385 static int select_invoke(bContext *C, wmOperator *op, wmEvent *event)
386 {
387         ARegion *ar= CTX_wm_region(C);
388         float co[2];
389
390         UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
391         RNA_float_set_array(op->ptr, "location", co);
392
393         return select_exec(C, op);
394 }
395
396 void CLIP_OT_select(wmOperatorType *ot)
397 {
398         /* identifiers */
399         ot->name= "Select";
400         ot->description= "Select tracking markers";
401         ot->idname= "CLIP_OT_select";
402
403         /* api callbacks */
404         ot->exec= select_exec;
405         ot->invoke= select_invoke;
406         ot->poll= space_clip_frame_poll;
407
408         /* flags */
409         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
410
411         /* properties */
412         RNA_def_boolean(ot->srna, "extend", 0,
413                 "Extend", "Extend selection rather than clearing the existing selection.");
414         RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
415                 "Location", "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds.", -100.0f, 100.0f);
416 }
417
418 /********************** border select operator *********************/
419
420 static int border_select_exec(bContext *C, wmOperator *op)
421 {
422         SpaceClip *sc= CTX_wm_space_clip(C);
423         MovieClip *clip= ED_space_clip(sc);
424         MovieTrackingTrack *track;
425         ARegion *ar= CTX_wm_region(C);
426         rcti rect;
427         rctf rectf;
428         int change= 0, mode;
429
430         /* get rectangle from operator */
431         rect.xmin= RNA_int_get(op->ptr, "xmin");
432         rect.ymin= RNA_int_get(op->ptr, "ymin");
433         rect.xmax= RNA_int_get(op->ptr, "xmax");
434         rect.ymax= RNA_int_get(op->ptr, "ymax");
435
436         UI_view2d_region_to_view(&ar->v2d, rect.xmin, rect.ymin, &rectf.xmin, &rectf.ymin);
437         UI_view2d_region_to_view(&ar->v2d, rect.xmax, rect.ymax, &rectf.xmax, &rectf.ymax);
438
439         mode= RNA_int_get(op->ptr, "gesture_mode");
440
441         /* do actual selection */
442         track= clip->tracking.tracks.first;
443         while(track) {
444                 MovieTrackingMarker *marker= BKE_tracking_get_marker(track, sc->user.framenr);
445
446                 if(marker) {
447                         if(BLI_in_rctf(&rectf, marker->pos[0], marker->pos[1])) {
448                                 BKE_tracking_track_flag(track, TRACK_AREA_ALL, SELECT, mode!=GESTURE_MODAL_SELECT);
449
450                                 change= 1;
451                         }
452                 }
453
454                 track= track->next;
455         }
456
457         BKE_movieclip_set_selection(clip, MCLIP_SEL_NONE, NULL);
458
459         if(change) {
460                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, NULL);
461
462                 return OPERATOR_FINISHED;
463         }
464
465         return OPERATOR_CANCELLED;
466 }
467
468 void CLIP_OT_select_border(wmOperatorType *ot)
469 {
470         /* identifiers */
471         ot->name= "Border Select";
472         ot->description= "Select markers using border selection";
473         ot->idname= "CLIP_OT_select_border";
474
475         /* api callbacks */
476         ot->invoke= WM_border_select_invoke;
477         ot->exec= border_select_exec;
478         ot->modal= WM_border_select_modal;
479         ot->poll= space_clip_frame_poll;
480
481         /* flags */
482         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
483
484         /* properties */
485         WM_operator_properties_gesture_border(ot, FALSE);
486 }
487
488 /********************** circle select operator *********************/
489
490 static int marker_inside_ellipse(MovieTrackingMarker *marker, float offset[2], float ellipse[2])
491 {
492         /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */
493         float x, y;
494
495         x= (marker->pos[0] - offset[0])*ellipse[0];
496         y= (marker->pos[1] - offset[1])*ellipse[1];
497
498         return x*x + y*y < 1.0f;
499 }
500
501 static int circle_select_exec(bContext *C, wmOperator *op)
502 {
503         SpaceClip *sc= CTX_wm_space_clip(C);
504         MovieClip *clip= ED_space_clip(sc);
505         ARegion *ar= CTX_wm_region(C);
506         MovieTrackingTrack *track;
507         int x, y, radius, width, height, mode, change= 0;
508         float zoomx, zoomy, offset[2], ellipse[2];
509
510         /* get operator properties */
511         x= RNA_int_get(op->ptr, "x");
512         y= RNA_int_get(op->ptr, "y");
513         radius= RNA_int_get(op->ptr, "radius");
514
515         mode= RNA_int_get(op->ptr, "gesture_mode");
516
517         /* compute ellipse and position in unified coordinates */
518         ED_space_clip_size(sc, &width, &height);
519         ED_space_clip_zoom(sc, ar, &zoomx, &zoomy);
520
521         ellipse[0]= width*zoomx/radius;
522         ellipse[1]= height*zoomy/radius;
523
524         UI_view2d_region_to_view(&ar->v2d, x, y, &offset[0], &offset[1]);
525
526         /* do selection */
527         track= clip->tracking.tracks.first;
528         while(track) {
529                 MovieTrackingMarker *marker= BKE_tracking_get_marker(track, sc->user.framenr);
530
531                 if(marker) {
532                         if(marker_inside_ellipse(marker, offset, ellipse)) {
533                                 BKE_tracking_track_flag(track, TRACK_AREA_ALL, SELECT, mode!=GESTURE_MODAL_SELECT);
534
535                                 change= 1;
536                         }
537                 }
538
539                 track= track->next;
540         }
541
542         BKE_movieclip_set_selection(clip, MCLIP_SEL_NONE, NULL);
543
544         if(change) {
545                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, NULL);
546
547                 return OPERATOR_FINISHED;
548         }
549
550         return OPERATOR_CANCELLED;
551 }
552
553 void CLIP_OT_select_circle(wmOperatorType *ot)
554 {
555         /* identifiers */
556         ot->name= "Circle Select";
557         ot->description= "Select markers using circle selection";
558         ot->idname= "CLIP_OT_select_circle";
559
560         /* api callbacks */
561         ot->invoke= WM_gesture_circle_invoke;
562         ot->modal= WM_gesture_circle_modal;
563         ot->exec= circle_select_exec;
564         ot->poll= space_clip_frame_poll;
565
566         /* flags */
567         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
568
569         /* properties */
570         RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
571         RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
572         RNA_def_int(ot->srna, "radius", 0, INT_MIN, INT_MAX, "Radius", "", INT_MIN, INT_MAX);
573         RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Gesture Mode", "", INT_MIN, INT_MAX);
574 }
575
576 /********************** select all operator *********************/
577
578 static int select_all_exec(bContext *C, wmOperator *op)
579 {
580         SpaceClip *sc= CTX_wm_space_clip(C);
581         MovieClip *clip= ED_space_clip(sc);
582         MovieTrackingTrack *track= NULL;        /* selected track */
583         int action= RNA_enum_get(op->ptr, "action");
584         int sel_type, framenr= sc->user.framenr;
585         void *sel;
586
587         if(action == SEL_TOGGLE){
588                 action= SEL_SELECT;
589                 track= clip->tracking.tracks.first;
590                 while(track) {
591                         if(BKE_tracking_has_marker(track, framenr)) {
592                                 if(TRACK_SELECTED(track)) {
593                                         action= SEL_DESELECT;
594                                         break;
595                                 }
596                         }
597
598                         track= track->next;
599                 }
600         }
601
602         track= clip->tracking.tracks.first;
603         while(track) {
604                 if(BKE_tracking_has_marker(track, framenr)) {
605                         switch (action) {
606                                 case SEL_SELECT:
607                                         if(track->bundle) track->bundle->flag|= SELECT;
608                                         track->flag|= SELECT;
609                                         track->pat_flag|= SELECT;
610                                         track->search_flag|= SELECT;
611                                         break;
612                                 case SEL_DESELECT:
613                                         if(track->bundle) track->bundle->flag&= ~SELECT;
614                                         track->flag&= ~SELECT;
615                                         track->pat_flag&= ~SELECT;
616                                         track->search_flag&= ~SELECT;
617                                         break;
618                                 case SEL_INVERT:
619                                         if(track->bundle) track->bundle->flag^= SELECT;
620                                         track->flag^= SELECT;
621                                         track->pat_flag^= SELECT;
622                                         track->search_flag^= SELECT;
623                                         break;
624                         }
625                 }
626
627                 track= track->next;
628         }
629
630         BKE_movieclip_last_selection(clip, &sel_type, &sel);
631         if(sel_type==MCLIP_SEL_TRACK)
632                 if(!TRACK_SELECTED(((MovieTrackingTrack*)sel)))
633                         BKE_movieclip_set_selection(clip, MCLIP_SEL_NONE, NULL);
634
635         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, NULL);
636
637         return OPERATOR_FINISHED;
638 }
639
640 void CLIP_OT_select_all(wmOperatorType *ot)
641 {
642         /* identifiers */
643         ot->name= "Select or Deselect All";
644         ot->description= "Change selection of all tracking markers";
645         ot->idname= "CLIP_OT_select_all";
646
647         /* api callbacks */
648         ot->exec= select_all_exec;
649         ot->poll= space_clip_frame_poll;
650
651         /* flags */
652         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
653
654         WM_operator_properties_select_all(ot);
655 }
656
657 /********************** track operator *********************/
658
659 typedef struct TrackMarkersJob {
660         struct MovieTrackingContext *context;   /* tracking context */
661         int sfra, efra, lastfra;        /* Start, end and recently tracked frames */
662         int backwards;                          /* Backwards tracking flag */
663         MovieClip *clip;                        /* Clip which is tracking */
664         float delay;                            /* Delay in milliseconds to allow tracking at fixed FPS */
665
666         struct Main *main;
667         struct Scene *scene;
668         struct bScreen *screen;
669 } TrackMarkersJob;
670
671 static int track_markers_testbreak(void)
672 {
673         return G.afbreek;
674 }
675
676 static void track_markers_initjob(bContext *C, TrackMarkersJob *tmj, int backwards)
677 {
678         SpaceClip *sc= CTX_wm_space_clip(C);
679         MovieClip *clip= ED_space_clip(sc);
680         Scene *scene= CTX_data_scene(C);
681         MovieTrackingSettings *settings= &clip->tracking.settings;
682
683         tmj->sfra= sc->user.framenr;
684         tmj->clip= clip;
685         tmj->backwards= backwards;
686
687         if(backwards) tmj->efra= SFRA;
688         else tmj->efra= EFRA;
689
690         /* limit frames to be tracked by user setting */
691         if(settings->flag&TRACKING_FRAMES_LIMIT) {
692                 if(backwards) tmj->efra= MAX2(tmj->efra, tmj->sfra-settings->frames_limit);
693                 else tmj->efra= MIN2(tmj->efra, tmj->sfra+settings->frames_limit);
694         }
695
696         if(settings->speed!=TRACKING_SPEED_FASTEST) {
697                 tmj->delay= 1.0f/scene->r.frs_sec*1000.0f;
698
699                 if(settings->speed==TRACKING_SPEED_HALF) tmj->delay*= 2;
700                 else if(settings->speed==TRACKING_SPEED_QUARTER) tmj->delay*= 4;
701         }
702
703         tmj->context= BKE_tracking_context_new(clip, &sc->user, backwards);
704
705         clip->tracking_context= tmj->context;
706
707         tmj->lastfra= tmj->sfra;
708
709         /* XXX: silly to store this, but this data is needed to update scene and movieclip
710                 frame numbers when tracking is finished. This introduces better feedback for artists.
711                 Maybe there's another way to solve this problem, but can't think better way atm.
712                 Anyway, this way isn't more unstable as animation rendering animation
713                 which uses the same approach (except storing screen). */
714         tmj->scene= scene;
715         tmj->main= CTX_data_main(C);
716         tmj->screen= CTX_wm_screen(C);
717 }
718
719 static void track_markers_startjob(void *tmv, short *UNUSED(stop), short *do_update, float *progress)
720 {
721         TrackMarkersJob *tmj= (TrackMarkersJob *)tmv;
722         int framenr= tmj->sfra;
723
724         while(framenr != tmj->efra) {
725                 if(tmj->delay>0) {
726                         /* tracking should happen with fixed fps. Calculate time
727                            using current timer value before tracking frame and after.
728
729                            Small (and maybe unneeded optimization): do not calculate exec_time
730                            for "Fastest" tracking */
731
732                         double start_time= PIL_check_seconds_timer(), exec_time;
733
734                         if(!BKE_tracking_next(tmj->context))
735                                 break;
736
737                         exec_time= PIL_check_seconds_timer()-start_time;
738                         if(tmj->delay>exec_time)
739                                 PIL_sleep_ms(tmj->delay-exec_time);
740                 } else if(!BKE_tracking_next(tmj->context))
741                                 break;
742
743                 *do_update= 1;
744                 *progress=(float)(framenr-tmj->sfra) / (tmj->efra-tmj->sfra);
745
746                 if(tmj->backwards) framenr--;
747                 else framenr++;
748
749                 tmj->lastfra= framenr;
750
751                 if(track_markers_testbreak())
752                         break;
753         }
754 }
755
756 static void track_markers_updatejob(void *tmv)
757 {
758         TrackMarkersJob *tmj= (TrackMarkersJob *)tmv;
759
760         BKE_tracking_sync(tmj->context);
761 }
762
763 static void track_markers_freejob(void *tmv)
764 {
765         TrackMarkersJob *tmj= (TrackMarkersJob *)tmv;
766
767         tmj->clip->tracking_context= NULL;
768         tmj->scene->r.cfra= tmj->lastfra;
769         ED_update_for_newframe(tmj->main, tmj->scene, tmj->screen, 0);
770
771         BKE_tracking_sync(tmj->context);
772         BKE_tracking_context_free(tmj->context);
773
774         MEM_freeN(tmj);
775
776         WM_main_add_notifier(NC_SCENE|ND_FRAME, tmj->scene);
777 }
778
779 static int track_markers_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
780 {
781         TrackMarkersJob *tmj;
782         SpaceClip *sc= CTX_wm_space_clip(C);
783         MovieClip *clip= ED_space_clip(sc);
784         wmJob *steve;
785         Scene *scene= CTX_data_scene(C);
786         int backwards= RNA_boolean_get(op->ptr, "backwards");
787
788         if(clip->tracking_context)
789                 return OPERATOR_CANCELLED;
790
791         tmj= MEM_callocN(sizeof(TrackMarkersJob), "TrackMarkersJob data");
792         track_markers_initjob(C, tmj, backwards);
793
794         /* setup job */
795         steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, "Track Markers", WM_JOB_EXCL_RENDER|WM_JOB_PRIORITY|WM_JOB_PROGRESS);
796         WM_jobs_customdata(steve, tmj, track_markers_freejob);
797
798         /* if there's delay set in tracking job, tracking should happen
799            with fixed FPS. To deal with editor refresh we have to syncronize
800            tracks from job and tracks in clip. Do this in timer callback
801            to prevent threading conflicts. */
802         if(tmj->delay>0) WM_jobs_timer(steve, tmj->delay/1000.0f, NC_MOVIECLIP|NA_EVALUATED, 0);
803         else WM_jobs_timer(steve, 0.2, NC_MOVIECLIP|NA_EVALUATED, 0);
804
805         WM_jobs_callbacks(steve, track_markers_startjob, NULL, track_markers_updatejob, NULL);
806
807         G.afbreek= 0;
808
809         WM_jobs_start(CTX_wm_manager(C), steve);
810         WM_cursor_wait(0);
811
812         /* add modal handler for ESC */
813         WM_event_add_modal_handler(C, op);
814
815         return OPERATOR_RUNNING_MODAL;
816 }
817
818 static int track_markers_exec(bContext *C, wmOperator *op)
819 {
820         SpaceClip *sc= CTX_wm_space_clip(C);
821         MovieClip *clip= ED_space_clip(sc);
822         Scene *scene= CTX_data_scene(C);
823         struct MovieTrackingContext *context;
824         int framenr= sc->user.framenr;
825         int sfra= framenr, efra;
826         int backwards= RNA_boolean_get(op->ptr, "backwards");
827         MovieTrackingSettings *settings= &clip->tracking.settings;
828
829         if(backwards) efra= SFRA;
830         else efra= EFRA;
831
832         /* limit frames to be tracked by user setting */
833         if(settings->flag&TRACKING_FRAMES_LIMIT) {
834                 if(backwards) efra= MAX2(efra, sfra-settings->frames_limit);
835                 else efra= MIN2(efra, sfra+settings->frames_limit);
836         }
837
838         context= BKE_tracking_context_new(clip, &sc->user, backwards);
839
840         while(framenr != efra) {
841                 if(!BKE_tracking_next(context))
842                         break;
843
844                 if(backwards) framenr--;
845                 else framenr++;
846         }
847
848         BKE_tracking_sync(context);
849         BKE_tracking_context_free(context);
850
851         /* update scene current frame to the lastes tracked frame */
852         scene->r.cfra= framenr;
853
854         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
855         WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
856
857         return OPERATOR_FINISHED;
858 }
859
860 static int track_marekrs_modal(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
861 {
862         /* no running blender, remove handler and pass through */
863         if(0==WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C)))
864                 return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
865
866         /* running tracking */
867         switch (event->type) {
868                 case ESCKEY:
869                         return OPERATOR_RUNNING_MODAL;
870                         break;
871         }
872
873         return OPERATOR_PASS_THROUGH;
874 }
875
876 void CLIP_OT_track_markers(wmOperatorType *ot)
877 {
878         /* identifiers */
879         ot->name= "Track Markers";
880         ot->description= "Track sleected markers";
881         ot->idname= "CLIP_OT_track_markers";
882
883         /* api callbacks */
884         ot->exec= track_markers_exec;
885         ot->invoke= track_markers_invoke;
886         ot->poll= space_clip_frame_poll;
887         ot->modal= track_marekrs_modal;
888
889         /* flags */
890         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
891
892         /* properties */
893         RNA_def_boolean(ot->srna, "backwards", 0, "Backwards", "Do backwards tarcking");
894 }
895
896 /********************** clear track operator *********************/
897
898 static int clear_track_path_poll(bContext *C)
899 {
900         SpaceClip *sc= CTX_wm_space_clip(C);
901
902         if(sc) {
903                 MovieClip *clip= ED_space_clip(sc);
904
905                 if(clip && BKE_movieclip_has_frame(clip, &sc->user)) {
906                         int sel_type;
907                         void *sel;
908
909                         BKE_movieclip_last_selection(clip, &sel_type, &sel);
910
911                         return sel_type == MCLIP_SEL_TRACK;
912                 }
913         }
914
915         return 0;
916 }
917
918 static int clear_track_path_exec(bContext *C, wmOperator *UNUSED(op))
919 {
920         SpaceClip *sc= CTX_wm_space_clip(C);
921         MovieClip *clip= ED_space_clip(sc);
922         int sel_type;
923         MovieTrackingTrack *track;
924
925         BKE_movieclip_last_selection(clip, &sel_type, (void**)&track);
926
927         BKE_tracking_clear_path(track, sc->user.framenr);
928
929         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
930
931         return OPERATOR_FINISHED;
932 }
933
934 void CLIP_OT_clear_track_path(wmOperatorType *ot)
935 {
936         /* identifiers */
937         ot->name= "Clear Track Path";
938         ot->description= "Clear path of active track";
939         ot->idname= "CLIP_OT_clear_track_path";
940
941         /* api callbacks */
942         ot->exec= clear_track_path_exec;
943         ot->poll= clear_track_path_poll;
944
945         /* flags */
946         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
947 }
948
949 /********************** track to fcurves opertaotr *********************/
950
951 static int track_to_fcurves_poll(bContext *C)
952 {
953         Object *ob= CTX_data_active_object(C);
954         SpaceClip *sc= CTX_wm_space_clip(C);
955
956         if(ob && sc) {
957                 MovieClip *clip= ED_space_clip(sc);
958                 int type;
959                 void *sel;
960
961                 if(clip) {
962                         BKE_movieclip_last_selection(clip, &type, &sel);
963                         if(type==MCLIP_SEL_TRACK)
964                                 return 1;
965                 }
966         }
967
968         return 0;
969 }
970
971 static int track_to_fcurves_exec(bContext *C, wmOperator *op)
972 {
973         SpaceClip *sc= CTX_wm_space_clip(C);
974         MovieClip *clip= ED_space_clip(sc);
975         Object *ob= CTX_data_active_object(C);
976         Scene *scene= CTX_data_scene(C);
977         KeyingSet *ks;
978         int kflag, fra= SFRA, type;
979         MovieTrackingTrack *track;
980         bAction *act= verify_adt_action(&ob->id, 1);
981         MovieClipUser user= {0};
982         int width, height;
983         float scale= RNA_float_get(op->ptr, "scale");
984
985         BKE_movieclip_last_selection(clip, &type, (void**)&track);
986
987         ks= ANIM_builtin_keyingset_get_named(NULL, "Location");
988         kflag= ks->flag;
989         kflag |= ANIM_get_keyframing_flags(scene, 1);
990
991         (void)op;
992
993         BKE_movieclip_acquire_size(clip, &user, &width, &height);
994
995         while(fra<EFRA) {
996                 MovieTrackingMarker *marker= BKE_tracking_get_marker(track, fra);
997
998                 if(marker) {
999                         FCurve *fcu;
1000
1001                         fcu= verify_fcurve(act, ks->name, "location", 0, 1);
1002                         insert_vert_fcurve(fcu, fra, marker->pos[0]*width*scale, kflag);
1003
1004                         fcu= verify_fcurve(act, ks->name, "location", 1, 1);
1005                         insert_vert_fcurve(fcu, fra, marker->pos[1]*height*scale, kflag);
1006                 }
1007
1008                 fra++;
1009         }
1010
1011         WM_main_add_notifier(NC_ANIMATION|ND_KEYFRAME|NA_EDITED, NULL);
1012
1013         return OPERATOR_FINISHED;
1014 }
1015
1016 void CLIP_OT_track_to_fcurves(wmOperatorType *ot)
1017 {
1018         /* identifiers */
1019         ot->name= "Convert Track To FCurves";
1020         ot->description= "Convert active track to f-curves for active object in the scene";
1021         ot->idname= "CLIP_OT_track_to_fcurves";
1022
1023         /* api callbacks */
1024         ot->exec= track_to_fcurves_exec;
1025         ot->poll= track_to_fcurves_poll;
1026
1027         /* flags */
1028         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1029
1030         RNA_def_float(ot->srna, "scale", 1.f, -FLT_MAX, FLT_MAX, "Scale", "Scale factor for generated coordinates", -100.f, 100.f);
1031 }