Camera tracking: if there's no image for current frame display
[blender.git] / source / blender / editors / space_clip / tracking_ops.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2011 Blender Foundation.
19  * All rights reserved.
20  *
21  *
22  * Contributor(s): Blender Foundation,
23  *                 Sergey Sharybin
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/space_clip/tracking_ops.c
29  *  \ingroup spclip
30  */
31
32 #include "MEM_guardedalloc.h"
33
34 #include "DNA_camera_types.h"
35 #include "DNA_constraint_types.h"
36 #include "DNA_gpencil_types.h"
37 #include "DNA_movieclip_types.h"
38 #include "DNA_object_types.h"   /* SELECT */
39 #include "DNA_scene_types.h"
40
41 #include "BLI_utildefines.h"
42 #include "BLI_math.h"
43 #include "BLI_listbase.h"
44 #include "BLI_rect.h"
45 #include "BLI_blenlib.h"
46
47 #include "BKE_main.h"
48 #include "BKE_context.h"
49 #include "BKE_constraint.h"
50 #include "BKE_movieclip.h"
51 #include "BKE_tracking.h"
52 #include "BKE_global.h"
53 #include "BKE_depsgraph.h"
54 #include "BKE_object.h"
55 #include "BKE_report.h"
56 #include "BKE_scene.h"
57 #include "BKE_library.h"
58 #include "BKE_sound.h"
59
60 #include "WM_api.h"
61 #include "WM_types.h"
62
63 #include "ED_screen.h"
64 #include "ED_clip.h"
65 #include "ED_keyframing.h"
66
67 #include "IMB_imbuf_types.h"
68 #include "IMB_imbuf.h"
69
70 #include "UI_interface.h"
71
72 #include "RNA_access.h"
73 #include "RNA_define.h"
74
75 #include "PIL_time.h"
76
77 #include "UI_view2d.h"
78
79 #include "clip_intern.h"        // own include
80
81 static int space_clip_frame_poll(bContext *C)
82 {
83         SpaceClip *sc = CTX_wm_space_clip(C);
84
85         if (sc) {
86                 MovieClip *clip = ED_space_clip(sc);
87
88                 if (clip)
89                         return BKE_movieclip_has_frame(clip, &sc->user);
90         }
91
92         return FALSE;
93 }
94
95 static int space_clip_size_poll(bContext *C)
96 {
97         SpaceClip *sc = CTX_wm_space_clip(C);
98
99         if (sc) {
100                 MovieClip *clip = ED_space_clip(sc);
101
102                 if (clip) {
103                         int width, height;
104
105                         BKE_movieclip_get_size(clip, &sc->user, &width, &height);
106
107                         return width > 0 && height > 0;
108                 }
109         }
110
111         return FALSE;
112 }
113
114 /********************** add marker operator *********************/
115
116 static void add_marker(SpaceClip *sc, float x, float y)
117 {
118         MovieClip *clip = ED_space_clip(sc);
119         MovieTracking *tracking = &clip->tracking;
120         ListBase *tracksbase = BKE_tracking_get_tracks(tracking);
121         MovieTrackingTrack *track;
122         int width, height;
123
124         ED_space_clip_size(sc, &width, &height);
125
126         track = BKE_tracking_add_track(tracking, tracksbase, x, y, sc->user.framenr, width, height);
127
128         BKE_tracking_select_track(tracksbase, track, TRACK_AREA_ALL, 0);
129
130         clip->tracking.act_track = track;
131 }
132
133 static int add_marker_exec(bContext *C, wmOperator *op)
134 {
135         SpaceClip *sc = CTX_wm_space_clip(C);
136         MovieClip *clip = ED_space_clip(sc);
137         float pos[2];
138         int width, height;
139
140         ED_space_clip_size(sc, &width, &height);
141         if (!width || !height)
142                 return OPERATOR_CANCELLED;
143
144         RNA_float_get_array(op->ptr, "location", pos);
145
146         add_marker(sc, pos[0], pos[1]);
147
148         /* reset offset from locked position, so frame jumping wouldn't be so confusing */
149         sc->xlockof = 0;
150         sc->ylockof = 0;
151
152         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, clip);
153
154         return OPERATOR_FINISHED;
155 }
156
157 static int add_marker_invoke(bContext *C, wmOperator *op, wmEvent *event)
158 {
159         float co[2];
160
161         ED_clip_mouse_pos(C, event, co);
162
163         RNA_float_set_array(op->ptr, "location", co);
164
165         return add_marker_exec(C, op);
166 }
167
168 void CLIP_OT_add_marker(wmOperatorType *ot)
169 {
170         /* identifiers */
171         ot->name = "Add Marker";
172         ot->idname = "CLIP_OT_add_marker";
173         ot->description = "Place new marker at specified location";
174
175         /* api callbacks */
176         ot->invoke = add_marker_invoke;
177         ot->exec = add_marker_exec;
178         ot->poll = space_clip_size_poll;
179
180         /* flags */
181         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
182
183         /* properties */
184         RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MIN, FLT_MAX,
185                 "Location", "Location of marker on frame", -1.0f, 1.0f);
186 }
187
188 /********************** delete track operator *********************/
189
190 static int delete_track_exec(bContext *C, wmOperator *UNUSED(op))
191 {
192         SpaceClip *sc = CTX_wm_space_clip(C);
193         MovieClip *clip = ED_space_clip(sc);
194         MovieTracking *tracking = &clip->tracking;
195         ListBase *tracksbase = BKE_tracking_get_tracks(tracking);
196         MovieTrackingTrack *track = tracksbase->first, *next;
197
198         while (track) {
199                 next = track->next;
200
201                 if (TRACK_VIEW_SELECTED(sc, track))
202                         clip_delete_track(C, clip, tracksbase, track);
203
204                 track = next;
205         }
206
207         /* nothing selected now, unlock view so it can be scrolled nice again */
208         sc->flag &= ~SC_LOCK_SELECTION;
209
210         return OPERATOR_FINISHED;
211 }
212
213 void CLIP_OT_delete_track(wmOperatorType *ot)
214 {
215         /* identifiers */
216         ot->name = "Delete Track";
217         ot->idname = "CLIP_OT_delete_track";
218         ot->description = "Delete selected tracks";
219
220         /* api callbacks */
221         ot->invoke = WM_operator_confirm;
222         ot->exec = delete_track_exec;
223         ot->poll = ED_space_clip_poll;
224
225         /* flags */
226         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
227 }
228
229 /********************** delete marker operator *********************/
230
231 static int delete_marker_exec(bContext *C, wmOperator *UNUSED(op))
232 {
233         SpaceClip *sc = CTX_wm_space_clip(C);
234         MovieClip *clip = ED_space_clip(sc);
235         ListBase *tracksbase = BKE_tracking_get_tracks(&clip->tracking);
236         MovieTrackingTrack *track = tracksbase->first, *next;
237         int framenr = sc->user.framenr;
238         int has_selection = 0;
239
240         while (track) {
241                 next = track->next;
242
243                 if (TRACK_VIEW_SELECTED(sc, track)) {
244                         MovieTrackingMarker *marker = BKE_tracking_exact_marker(track, framenr);
245
246                         if (marker) {
247                                 has_selection |= track->markersnr>1;
248
249                                 clip_delete_marker(C, clip, tracksbase, track, marker);
250                         }
251                 }
252
253                 track = next;
254         }
255
256         if (!has_selection) {
257                 /* nothing selected now, unlock view so it can be scrolled nice again */
258                 sc->flag &= ~SC_LOCK_SELECTION;
259         }
260
261         return OPERATOR_FINISHED;
262 }
263
264 void CLIP_OT_delete_marker(wmOperatorType *ot)
265 {
266         /* identifiers */
267         ot->name = "Delete Marker";
268         ot->idname = "CLIP_OT_delete_marker";
269         ot->description = "Delete marker for current frame from selected tracks";
270
271         /* api callbacks */
272         ot->invoke = WM_operator_confirm;
273         ot->exec = delete_marker_exec;
274         ot->poll = ED_space_clip_poll;
275
276         /* flags */
277         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
278 }
279
280 /********************** slide marker operator *********************/
281
282 #define SLIDE_ACTION_POS        0
283 #define SLIDE_ACTION_SIZE       1
284 #define SLIDE_ACTION_OFFSET     2
285
286 typedef struct {
287         int area, action;
288         MovieTrackingTrack *track;
289         MovieTrackingMarker *marker;
290
291         int mval[2];
292         int width, height;
293         float *min, *max, *pos, *offset;
294         float smin[2], smax[2], spos[2], soff[2];
295         float (*smarkers)[2];
296
297         int lock, accurate;
298 } SlideMarkerData;
299
300 static SlideMarkerData *create_slide_marker_data(SpaceClip *sc, MovieTrackingTrack *track,
301                         MovieTrackingMarker *marker, wmEvent *event, int area, int action, int width, int height)
302 {
303         SlideMarkerData *data = MEM_callocN(sizeof(SlideMarkerData), "slide marker data");
304
305         marker = BKE_tracking_ensure_marker(track, sc->user.framenr);
306
307         data->area = area;
308         data->action = action;
309         data->track = track;
310         data->marker = marker;
311
312         if (area == TRACK_AREA_POINT) {
313                 data->pos = marker->pos;
314                 data->offset = track->offset;
315                 copy_v2_v2(data->spos, marker->pos);
316                 copy_v2_v2(data->soff, track->offset);
317         }
318         else if (area == TRACK_AREA_PAT) {
319                 if (action == SLIDE_ACTION_SIZE) {
320                         data->min = track->pat_min;
321                         data->max = track->pat_max;
322                 }
323                 else {
324                         int a;
325
326                         data->pos = marker->pos;
327                         data->offset = track->offset;
328
329                         copy_v2_v2(data->soff, track->offset);
330
331                         data->smarkers = MEM_callocN(sizeof(*data->smarkers)*track->markersnr, "slide marekrs");
332                         for (a = 0; a < track->markersnr; a++)
333                                 copy_v2_v2(data->smarkers[a], track->markers[a].pos);
334                 }
335         }
336         else if (area == TRACK_AREA_SEARCH) {
337                 data->min = track->search_min;
338                 data->max = track->search_max;
339         }
340
341         if (area == TRACK_AREA_SEARCH || (area == TRACK_AREA_PAT && action != SLIDE_ACTION_OFFSET)) {
342                 copy_v2_v2(data->smin, data->min);
343                 copy_v2_v2(data->smax, data->max);
344         }
345
346         data->mval[0] = event->mval[0];
347         data->mval[1] = event->mval[1];
348
349         data->width = width;
350         data->height = height;
351
352         if (action == SLIDE_ACTION_SIZE)
353                 data->lock = 1;
354
355         return data;
356 }
357
358 /* corner = 0: right-bottom corner,
359  * corner = 1: left-top corner */
360 static int mouse_on_corner(SpaceClip *sc, MovieTrackingTrack *track, MovieTrackingMarker *marker,
361                            int area, float co[2], int corner, int width, int height)
362 {
363         int inside = 0;
364         float size = 12.0f;
365         float min[2], max[2];
366         float crn[2], dx, dy, tdx, tdy;
367
368         if (area == TRACK_AREA_SEARCH) {
369                 copy_v2_v2(min, track->search_min);
370                 copy_v2_v2(max, track->search_max);
371         }
372         else {
373                 copy_v2_v2(min, track->pat_min);
374                 copy_v2_v2(max, track->pat_max);
375         }
376
377         dx = size / width / sc->zoom;
378         dy = size / height / sc->zoom;
379
380         tdx = 5.0f / width / sc->zoom;
381         tdy = 5.0f / height / sc->zoom;
382
383         dx = MIN2(dx, (max[0] - min[0]) / 6.0f) + tdx;
384         dy = MIN2(dy, (max[1] - min[1]) / 6.0f) + tdy;
385
386         if (corner == 0) {
387                 crn[0] = marker->pos[0] + max[0];
388                 crn[1] = marker->pos[1] + min[1];
389
390                 inside = co[0] >= crn[0] - dx && co[0] <= crn[0] + tdx && co[1] >= crn[1] - tdy && co[1] <= crn[1] + dy;
391         }
392         else {
393                 crn[0] = marker->pos[0]+min[0];
394                 crn[1] = marker->pos[1]+max[1];
395
396                 inside = co[0] >= crn[0] - dx && co[0] <= crn[0] + dx && co[1] >= crn[1] - dy && co[1] <= crn[1] + dy;
397         }
398
399         return inside;
400 }
401
402 static int mouse_on_offset(SpaceClip *sc, MovieTrackingTrack *track, MovieTrackingMarker *marker,
403                         float co[2], int width, int height)
404 {
405         float pos[2], dx, dy;
406
407         add_v2_v2v2(pos, marker->pos, track->offset);
408
409         dx = 12.0f / width / sc->zoom;
410         dy = 12.0f / height /sc->zoom;
411
412         dx = MIN2(dx, (track->pat_max[0] - track->pat_min[0]) / 2.0f);
413         dy = MIN2(dy, (track->pat_max[1] - track->pat_min[1]) / 2.0f);
414
415         return co[0] >= pos[0] - dx && co[0] <= pos[0] + dx && co[1] >= pos[1] - dy && co[1] <= pos[1] + dy;
416 }
417
418 static void hide_cursor(bContext *C)
419 {
420         wmWindow *win = CTX_wm_window(C);
421
422         WM_cursor_set(win, CURSOR_NONE);
423 }
424
425 static void show_cursor(bContext *C)
426 {
427         wmWindow *win = CTX_wm_window(C);
428
429         WM_cursor_set(win, CURSOR_STD);
430 }
431
432 static void *slide_marker_customdata(bContext *C, wmEvent *event)
433 {
434         SpaceClip *sc = CTX_wm_space_clip(C);
435         MovieClip *clip = ED_space_clip(sc);
436         MovieTrackingTrack *track;
437         int width, height;
438         float co[2];
439         void *customdata = NULL;
440         ListBase *tracksbase = BKE_tracking_get_tracks(&clip->tracking);
441
442         ED_space_clip_size(sc, &width, &height);
443
444         if (width == 0 || height == 0)
445                 return NULL;
446
447         ED_clip_mouse_pos(C, event, co);
448
449         track = tracksbase->first;
450         while (track) {
451                 if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) {
452                         MovieTrackingMarker *marker = BKE_tracking_get_marker(track, sc->user.framenr);
453
454                         if ((marker->flag & MARKER_DISABLED) == 0) {
455                                 if (!customdata)
456                                         if (mouse_on_offset(sc, track, marker, co, width, height))
457                                                 customdata = create_slide_marker_data(sc, track, marker, event, TRACK_AREA_POINT, SLIDE_ACTION_POS, width, height);
458
459                                 if (sc->flag & SC_SHOW_MARKER_SEARCH) {
460                                         if (mouse_on_corner(sc, track, marker, TRACK_AREA_SEARCH, co, 1, width, height))
461                                                 customdata = create_slide_marker_data(sc, track, marker, event, TRACK_AREA_SEARCH, SLIDE_ACTION_OFFSET, width, height);
462                                         else if (mouse_on_corner(sc, track, marker, TRACK_AREA_SEARCH, co, 0, width, height))
463                                                 customdata = create_slide_marker_data(sc, track, marker, event, TRACK_AREA_SEARCH, SLIDE_ACTION_SIZE, width, height);
464                                 }
465
466                                 if (!customdata && (sc->flag & SC_SHOW_MARKER_PATTERN)) {
467                                         if (mouse_on_corner(sc, track, marker, TRACK_AREA_PAT, co, 1,  width, height))
468                                                 customdata = create_slide_marker_data(sc, track, marker, event, TRACK_AREA_PAT, SLIDE_ACTION_OFFSET, width, height);
469
470                                         if (!customdata && mouse_on_corner(sc, track, marker, TRACK_AREA_PAT, co, 0, width, height))
471                                                 customdata = create_slide_marker_data(sc, track, marker, event, TRACK_AREA_PAT, SLIDE_ACTION_SIZE, width, height);
472                                 }
473
474                                 if (customdata)
475                                         break;
476                         }
477                 }
478
479                 track = track->next;
480         }
481
482         return customdata;
483 }
484
485 static int slide_marker_invoke(bContext *C, wmOperator *op, wmEvent *event)
486 {
487         SlideMarkerData *slidedata = slide_marker_customdata(C, event);
488
489         if (slidedata) {
490                 SpaceClip *sc = CTX_wm_space_clip(C);
491                 MovieClip *clip = ED_space_clip(sc);
492                 MovieTracking *tracking = &clip->tracking;
493
494                 tracking->act_track = slidedata->track;
495
496                 op->customdata = slidedata;
497
498                 hide_cursor(C);
499                 WM_event_add_modal_handler(C, op);
500
501                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, NULL);
502
503                 return OPERATOR_RUNNING_MODAL;
504         }
505
506         return OPERATOR_PASS_THROUGH;
507 }
508
509 static void cancel_mouse_slide(SlideMarkerData *data)
510 {
511         /* cancel sliding */
512         if (data->area == TRACK_AREA_POINT) {
513                 if (data->action == SLIDE_ACTION_OFFSET)
514                         copy_v2_v2(data->offset, data->soff);
515                 else
516                         copy_v2_v2(data->pos, data->spos);
517         }
518         else {
519                 if (data->action == SLIDE_ACTION_SIZE) {
520                         copy_v2_v2(data->min, data->smin);
521                         copy_v2_v2(data->max, data->smax);
522                 }
523                 else {
524                         int a;
525
526                         for (a = 0; a<data->track->markersnr; a++)
527                                 copy_v2_v2(data->track->markers[a].pos, data->smarkers[a]);
528
529                         copy_v2_v2(data->offset, data->soff);
530                 }
531         }
532 }
533
534 static void free_slide_data(SlideMarkerData *data)
535 {
536         if (data->smarkers)
537                 MEM_freeN(data->smarkers);
538
539         MEM_freeN(data);
540 }
541
542 static int slide_marker_modal(bContext *C, wmOperator *op, wmEvent *event)
543 {
544         SpaceClip *sc = CTX_wm_space_clip(C);
545         SlideMarkerData *data = (SlideMarkerData *)op->customdata;
546         float dx, dy, mdelta[2];
547
548         switch(event->type) {
549                 case LEFTCTRLKEY:
550                 case RIGHTCTRLKEY:
551                 case LEFTSHIFTKEY:
552                 case RIGHTSHIFTKEY:
553                         if (data->action == SLIDE_ACTION_SIZE)
554                                 if (ELEM(event->type, LEFTCTRLKEY, RIGHTCTRLKEY))
555                                         data->lock = event->val == KM_RELEASE;
556
557                         if (ELEM(event->type, LEFTSHIFTKEY, RIGHTSHIFTKEY))
558                                 data->accurate = event->val == KM_PRESS;
559
560                         /* no break! update area size */
561
562                 case MOUSEMOVE:
563                         mdelta[0] = event->mval[0]-data->mval[0];
564                         mdelta[1] = event->mval[1]-data->mval[1];
565
566                         dx = mdelta[0] / data->width / sc->zoom;
567
568                         if (data->lock)
569                                 dy = -dx / data->height * data->width;
570                         else
571                                 dy = mdelta[1] / data->height / sc->zoom;
572
573                         if (data->accurate) {
574                                 dx /= 5;
575                                 dy /= 5;
576                         }
577
578                         if (data->area == TRACK_AREA_POINT) {
579                                 if (data->action == SLIDE_ACTION_OFFSET) {
580                                         data->offset[0] = data->soff[0] + dx;
581                                         data->offset[1] = data->soff[1] + dy;
582                                 }
583                                 else {
584                                         data->pos[0] = data->spos[0] + dx;
585                                         data->pos[1] = data->spos[1] + dy;
586
587                                         data->marker->flag &= ~MARKER_TRACKED;
588                                 }
589
590                                 WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
591                                 DAG_id_tag_update(&sc->clip->id, 0);
592                         }
593                         else {
594                                 if (data->action == SLIDE_ACTION_SIZE) {
595                                         data->min[0] = data->smin[0] - dx;
596                                         data->max[0] = data->smax[0] + dx;
597
598                                         data->min[1] = data->smin[1] + dy;
599                                         data->max[1] = data->smax[1] - dy;
600
601                                         if (data->area == TRACK_AREA_SEARCH)
602                                                 BKE_tracking_clamp_track(data->track, CLAMP_SEARCH_DIM);
603                                         else
604                                                 BKE_tracking_clamp_track(data->track, CLAMP_PAT_DIM);
605                                 }
606                                 else {
607                                         float d[2] = {dx, dy};
608
609                                         if (data->area == TRACK_AREA_SEARCH) {
610                                                 add_v2_v2v2(data->min, data->smin, d);
611                                                 add_v2_v2v2(data->max, data->smax, d);
612                                         }
613                                         else {
614                                                 int a;
615
616                                                 for (a = 0; a<data->track->markersnr; a++)
617                                                         add_v2_v2v2(data->track->markers[a].pos, data->smarkers[a], d);
618
619                                                 sub_v2_v2v2(data->offset, data->soff, d);
620                                         }
621
622                                         if (data->area == TRACK_AREA_SEARCH)
623                                                 BKE_tracking_clamp_track(data->track, CLAMP_SEARCH_POS);
624                                 }
625                         }
626
627                         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, NULL);
628
629                         break;
630
631                 case LEFTMOUSE:
632                         if (event->val == KM_RELEASE) {
633                                 free_slide_data(op->customdata);
634
635                                 show_cursor(C);
636
637                                 return OPERATOR_FINISHED;
638                         }
639
640                         break;
641
642                 case ESCKEY:
643                         cancel_mouse_slide(op->customdata);
644
645                         free_slide_data(op->customdata);
646
647                         show_cursor(C);
648
649                         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, NULL);
650
651                         return OPERATOR_CANCELLED;
652         }
653
654         return OPERATOR_RUNNING_MODAL;
655 }
656
657 void CLIP_OT_slide_marker(wmOperatorType *ot)
658 {
659         /* identifiers */
660         ot->name = "Slide Marker";
661         ot->description = "Slide marker areas";
662         ot->idname = "CLIP_OT_slide_marker";
663
664         /* api callbacks */
665         ot->poll = space_clip_size_poll;
666         ot->invoke = slide_marker_invoke;
667         ot->modal = slide_marker_modal;
668
669         /* flags */
670         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_GRAB_POINTER|OPTYPE_BLOCKING;
671
672         /* properties */
673         RNA_def_float_vector(ot->srna, "offset", 2, NULL, -FLT_MAX, FLT_MAX,
674                 "Offset", "Offset in floating point units, 1.0 is the width and height of the image", -FLT_MAX, FLT_MAX);
675 }
676
677 /********************** mouse select operator *********************/
678
679 static int mouse_on_side(float co[2], float x1, float y1, float x2, float y2, float epsx, float epsy)
680 {
681         if (x1 > x2)
682
683                 SWAP(float, x1, x2);
684
685         if (y1 > y2)
686                 SWAP(float, y1, y2);
687
688         return (co[0] >= x1 - epsx && co[0] <= x2 + epsx) && (co[1] >= y1 - epsy && co[1] <= y2 + epsy);
689 }
690
691 static int mouse_on_rect(float co[2], float pos[2], float min[2], float max[2], float epsx, float epsy)
692 {
693         return mouse_on_side(co, pos[0]+min[0], pos[1]+min[1], pos[0]+max[0], pos[1]+min[1], epsx, epsy) ||
694                mouse_on_side(co, pos[0]+min[0], pos[1]+min[1], pos[0]+min[0], pos[1]+max[1], epsx, epsy) ||
695                mouse_on_side(co, pos[0]+min[0], pos[1]+max[1], pos[0]+max[0], pos[1]+max[1], epsx, epsy) ||
696                mouse_on_side(co, pos[0]+max[0], pos[1]+min[1], pos[0]+max[0], pos[1]+max[1], epsx, epsy);
697 }
698
699 static int track_mouse_area(SpaceClip *sc, float co[2], MovieTrackingTrack *track)
700 {
701         MovieTrackingMarker *marker = BKE_tracking_get_marker(track, sc->user.framenr);
702         float epsx, epsy;
703         int width, height;
704
705         ED_space_clip_size(sc, &width, &height);
706
707         epsx = MIN4(track->pat_min[0]-track->search_min[0], track->search_max[0]-track->pat_max[0],
708                    fabsf(track->pat_min[0]), fabsf(track->pat_max[0])) / 2;
709         epsy = MIN4(track->pat_min[1]-track->search_min[1], track->search_max[1]-track->pat_max[1],
710                    fabsf(track->pat_min[1]), fabsf(track->pat_max[1])) / 2;
711
712         epsx = MAX2(epsx, 2.0f / width);
713         epsy = MAX2(epsy, 2.0f / height);
714
715         if (sc->flag & SC_SHOW_MARKER_SEARCH) {
716                 if (mouse_on_rect(co, marker->pos, track->search_min, track->search_max, epsx, epsy))
717                         return TRACK_AREA_SEARCH;
718         }
719
720         if ((marker->flag & MARKER_DISABLED)== 0) {
721                 if (sc->flag & SC_SHOW_MARKER_PATTERN)
722                         if (mouse_on_rect(co, marker->pos, track->pat_min, track->pat_max, epsx, epsy))
723                                 return TRACK_AREA_PAT;
724
725                 epsx = 12.0f / width;
726                 epsy = 12.0f / height;
727
728                 if (fabsf(co[0]-marker->pos[0]-track->offset[0])< epsx && fabsf(co[1]-marker->pos[1]-track->offset[1])<=epsy)
729                         return TRACK_AREA_POINT;
730         }
731
732         return TRACK_AREA_NONE;
733 }
734
735 static float dist_to_rect(float co[2], float pos[2], float min[2], float max[2])
736 {
737         float d1, d2, d3, d4;
738         float p[2] = {co[0]-pos[0], co[1]-pos[1]};
739         float v1[2] = {min[0], min[1]}, v2[2] = {max[0], min[1]},
740               v3[2] = {max[0], max[1]}, v4[2] = {min[0], max[1]};
741
742         d1 = dist_to_line_segment_v2(p, v1, v2);
743         d2 = dist_to_line_segment_v2(p, v2, v3);
744         d3 = dist_to_line_segment_v2(p, v3, v4);
745         d4 = dist_to_line_segment_v2(p, v4, v1);
746
747         return MIN4(d1, d2, d3, d4);
748 }
749
750 static MovieTrackingTrack *find_nearest_track(SpaceClip *sc, ListBase *tracksbase, float co[2])
751 {
752         MovieTrackingTrack *track = NULL, *cur;
753         float mindist = 0.0f;
754
755         cur = tracksbase->first;
756         while (cur) {
757                 MovieTrackingMarker *marker = BKE_tracking_get_marker(cur, sc->user.framenr);
758
759                 if (((cur->flag & TRACK_HIDDEN) == 0) && MARKER_VISIBLE(sc, marker)) {
760                         float dist, d1, d2 = FLT_MAX, d3 = FLT_MAX;
761
762                         d1= sqrtf((co[0]-marker->pos[0]-cur->offset[0])*(co[0]-marker->pos[0]-cur->offset[0])+
763                                           (co[1]-marker->pos[1]-cur->offset[1])*(co[1]-marker->pos[1]-cur->offset[1])); /* distance to marker point */
764
765                         /* distance to pattern boundbox */
766                         if (sc->flag & SC_SHOW_MARKER_PATTERN)
767                                 d2= dist_to_rect(co, marker->pos, cur->pat_min, cur->pat_max);
768
769                         /* distance to search boundbox */
770                         if (sc->flag & SC_SHOW_MARKER_SEARCH && TRACK_VIEW_SELECTED(sc, cur))
771                                 d3= dist_to_rect(co, marker->pos, cur->search_min, cur->search_max);
772
773                         /* choose minimal distance. useful for cases of overlapped markers. */
774                         dist = MIN3(d1, d2, d3);
775
776                         if (track == NULL || dist<mindist) {
777                                 track = cur;
778                                 mindist = dist;
779                         }
780                 }
781
782                 cur = cur->next;
783         }
784
785         return track;
786 }
787
788 static int mouse_select(bContext *C, float co[2], int extend)
789 {
790         SpaceClip *sc = CTX_wm_space_clip(C);
791         MovieClip *clip = ED_space_clip(sc);
792         MovieTracking *tracking = &clip->tracking;
793         ListBase *tracksbase = BKE_tracking_get_tracks(tracking);
794         MovieTrackingTrack *act_track = BKE_tracking_active_track(tracking);
795         MovieTrackingTrack *track = NULL;       /* selected marker */
796
797         track = find_nearest_track(sc, tracksbase, co);
798
799         if (track) {
800                 int area = track_mouse_area(sc, co, track);
801
802                 if (!extend || !TRACK_VIEW_SELECTED(sc, track))
803                         area = TRACK_AREA_ALL;
804
805                 if (extend && TRACK_AREA_SELECTED(track, area)) {
806                         if (track == act_track)
807                                 BKE_tracking_deselect_track(track, area);
808                         else
809                                 clip->tracking.act_track = track;
810                 }
811                 else {
812                         if (area == TRACK_AREA_POINT)
813                                 area = TRACK_AREA_ALL;
814
815                         BKE_tracking_select_track(tracksbase, track, area, extend);
816                         clip->tracking.act_track = track;
817                 }
818         }
819
820         if (!extend) {
821                 sc->xlockof = 0.0f;
822                 sc->ylockof = 0.0f;
823         }
824
825         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, NULL);
826
827         return OPERATOR_FINISHED;
828 }
829
830 static int select_exec(bContext *C, wmOperator *op)
831 {
832         float co[2];
833         int extend;
834
835         RNA_float_get_array(op->ptr, "location", co);
836         extend = RNA_boolean_get(op->ptr, "extend");
837
838         return mouse_select(C, co, extend);
839 }
840
841 static int select_invoke(bContext *C, wmOperator *op, wmEvent *event)
842 {
843         float co[2];
844         int extend = RNA_boolean_get(op->ptr, "extend");
845
846         if (!extend) {
847                 SlideMarkerData *slidedata = slide_marker_customdata(C, event);
848
849                 if (slidedata) {
850                         SpaceClip *sc = CTX_wm_space_clip(C);
851                         MovieClip *clip = ED_space_clip(sc);
852
853                         clip->tracking.act_track = slidedata->track;
854
855                         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, NULL);
856
857                         MEM_freeN(slidedata);
858
859                         return OPERATOR_PASS_THROUGH;
860                 }
861         }
862
863         ED_clip_mouse_pos(C, event, co);
864         RNA_float_set_array(op->ptr, "location", co);
865
866         return select_exec(C, op);
867 }
868
869 void CLIP_OT_select(wmOperatorType *ot)
870 {
871         /* identifiers */
872         ot->name = "Select";
873         ot->description = "Select tracking markers";
874         ot->idname = "CLIP_OT_select";
875
876         /* api callbacks */
877         ot->exec = select_exec;
878         ot->invoke = select_invoke;
879         ot->poll = ED_space_clip_poll;
880
881         /* flags */
882         ot->flag = OPTYPE_UNDO;
883
884         /* properties */
885         RNA_def_boolean(ot->srna, "extend", 0,
886                 "Extend", "Extend selection rather than clearing the existing selection");
887         RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
888                 "Location", "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds", -100.0f, 100.0f);
889 }
890
891 /********************** border select operator *********************/
892
893 static int border_select_exec(bContext *C, wmOperator *op)
894 {
895         SpaceClip *sc = CTX_wm_space_clip(C);
896         MovieClip *clip = ED_space_clip(sc);
897         MovieTrackingTrack *track;
898         ListBase *tracksbase = BKE_tracking_get_tracks(&clip->tracking);
899         rcti rect;
900         rctf rectf;
901         int change = FALSE, mode, extend;
902
903         /* get rectangle from operator */
904         rect.xmin = RNA_int_get(op->ptr, "xmin");
905         rect.ymin = RNA_int_get(op->ptr, "ymin");
906         rect.xmax = RNA_int_get(op->ptr, "xmax");
907         rect.ymax = RNA_int_get(op->ptr, "ymax");
908
909         ED_clip_point_stable_pos(C, rect.xmin, rect.ymin, &rectf.xmin, &rectf.ymin);
910         ED_clip_point_stable_pos(C, rect.xmax, rect.ymax, &rectf.xmax, &rectf.ymax);
911
912         mode = RNA_int_get(op->ptr, "gesture_mode");
913         extend = RNA_boolean_get(op->ptr, "extend");
914
915         /* do actual selection */
916         track = tracksbase->first;
917         while (track) {
918                 if ((track->flag & TRACK_HIDDEN) == 0) {
919                         MovieTrackingMarker *marker = BKE_tracking_get_marker(track, sc->user.framenr);
920
921                         if (MARKER_VISIBLE(sc, marker)) {
922                                 if (BLI_in_rctf(&rectf, marker->pos[0], marker->pos[1])) {
923                                         BKE_tracking_track_flag(track, TRACK_AREA_ALL, SELECT, mode!=GESTURE_MODAL_SELECT);
924                                 }
925                                 else if (!extend) {
926                                         BKE_tracking_track_flag(track, TRACK_AREA_ALL, SELECT, 1);
927                                 }
928
929                                 change = TRUE;
930                         }
931                 }
932
933                 track = track->next;
934         }
935
936         if (change) {
937                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, NULL);
938
939                 return OPERATOR_FINISHED;
940         }
941
942         return OPERATOR_CANCELLED;
943 }
944
945 void CLIP_OT_select_border(wmOperatorType *ot)
946 {
947         /* identifiers */
948         ot->name = "Border Select";
949         ot->description = "Select markers using border selection";
950         ot->idname = "CLIP_OT_select_border";
951
952         /* api callbacks */
953         ot->invoke = WM_border_select_invoke;
954         ot->exec = border_select_exec;
955         ot->modal = WM_border_select_modal;
956         ot->poll = ED_space_clip_poll;
957
958         /* flags */
959         ot->flag = OPTYPE_UNDO;
960
961         /* properties */
962         WM_operator_properties_gesture_border(ot, TRUE);
963 }
964
965 /********************** circle select operator *********************/
966
967 static int marker_inside_ellipse(MovieTrackingMarker *marker, float offset[2], float ellipse[2])
968 {
969         /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */
970         float x, y;
971
972         x = (marker->pos[0] - offset[0])*ellipse[0];
973         y = (marker->pos[1] - offset[1])*ellipse[1];
974
975         return x*x + y*y < 1.0f;
976 }
977
978 static int circle_select_exec(bContext *C, wmOperator *op)
979 {
980         SpaceClip *sc = CTX_wm_space_clip(C);
981         MovieClip *clip = ED_space_clip(sc);
982         ARegion *ar = CTX_wm_region(C);
983         MovieTrackingTrack *track;
984         ListBase *tracksbase = BKE_tracking_get_tracks(&clip->tracking);
985         int x, y, radius, width, height, mode, change = FALSE;
986         float zoomx, zoomy, offset[2], ellipse[2];
987
988         /* get operator properties */
989         x = RNA_int_get(op->ptr, "x");
990         y = RNA_int_get(op->ptr, "y");
991         radius = RNA_int_get(op->ptr, "radius");
992
993         mode = RNA_int_get(op->ptr, "gesture_mode");
994
995         /* compute ellipse and position in unified coordinates */
996         ED_space_clip_size(sc, &width, &height);
997         ED_space_clip_zoom(sc, ar, &zoomx, &zoomy);
998
999         ellipse[0] = width * zoomx / radius;
1000         ellipse[1] = height * zoomy / radius;
1001
1002         ED_clip_point_stable_pos(C, x, y, &offset[0], &offset[1]);
1003
1004         /* do selection */
1005         track = tracksbase->first;
1006         while (track) {
1007                 if ((track->flag & TRACK_HIDDEN) == 0) {
1008                         MovieTrackingMarker *marker = BKE_tracking_get_marker(track, sc->user.framenr);
1009
1010                         if (MARKER_VISIBLE(sc, marker) && marker_inside_ellipse(marker, offset, ellipse)) {
1011                                 BKE_tracking_track_flag(track, TRACK_AREA_ALL, SELECT, mode!=GESTURE_MODAL_SELECT);
1012
1013                                 change = TRUE;
1014                         }
1015                 }
1016
1017                 track = track->next;
1018         }
1019
1020         if (change) {
1021                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, NULL);
1022
1023                 return OPERATOR_FINISHED;
1024         }
1025
1026         return OPERATOR_CANCELLED;
1027 }
1028
1029 void CLIP_OT_select_circle(wmOperatorType *ot)
1030 {
1031         /* identifiers */
1032         ot->name = "Circle Select";
1033         ot->description = "Select markers using circle selection";
1034         ot->idname = "CLIP_OT_select_circle";
1035
1036         /* api callbacks */
1037         ot->invoke = WM_gesture_circle_invoke;
1038         ot->modal = WM_gesture_circle_modal;
1039         ot->exec = circle_select_exec;
1040         ot->poll = ED_space_clip_poll;
1041
1042         /* flags */
1043         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
1044
1045         /* properties */
1046         RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
1047         RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
1048         RNA_def_int(ot->srna, "radius", 0, INT_MIN, INT_MAX, "Radius", "", INT_MIN, INT_MAX);
1049         RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Gesture Mode", "", INT_MIN, INT_MAX);
1050 }
1051
1052 /********************** select all operator *********************/
1053
1054 static int select_all_exec(bContext *C, wmOperator *op)
1055 {
1056         SpaceClip *sc = CTX_wm_space_clip(C);
1057         MovieClip *clip = ED_space_clip(sc);
1058         MovieTrackingTrack *track = NULL;       /* selected track */
1059         MovieTrackingMarker *marker;
1060         ListBase *tracksbase = BKE_tracking_get_tracks(&clip->tracking);
1061         int action = RNA_enum_get(op->ptr, "action");
1062         int framenr = sc->user.framenr;
1063         int has_selection = FALSE;
1064
1065         if (action == SEL_TOGGLE) {
1066                 action = SEL_SELECT;
1067                 track = tracksbase->first;
1068                 while (track) {
1069                         if (TRACK_VIEW_SELECTED(sc, track)) {
1070                                 marker = BKE_tracking_get_marker(track, framenr);
1071
1072                                 if (MARKER_VISIBLE(sc, marker)) {
1073                                         action = SEL_DESELECT;
1074                                         break;
1075                                 }
1076                         }
1077
1078                         track = track->next;
1079                 }
1080         }
1081
1082         track = tracksbase->first;
1083         while (track) {
1084                 if ((track->flag & TRACK_HIDDEN)==0) {
1085                         marker = BKE_tracking_get_marker(track, framenr);
1086
1087                         if (MARKER_VISIBLE(sc, marker)) {
1088                                 switch (action) {
1089                                         case SEL_SELECT:
1090                                                 track->flag |= SELECT;
1091                                                 track->pat_flag |= SELECT;
1092                                                 track->search_flag |= SELECT;
1093                                                 break;
1094                                         case SEL_DESELECT:
1095                                                 track->flag &= ~SELECT;
1096                                                 track->pat_flag &= ~SELECT;
1097                                                 track->search_flag &= ~SELECT;
1098                                                 break;
1099                                         case SEL_INVERT:
1100                                                 track->flag ^= SELECT;
1101                                                 track->pat_flag ^= SELECT;
1102                                                 track->search_flag ^= SELECT;
1103                                                 break;
1104                                 }
1105                         }
1106                 }
1107
1108                 if (TRACK_VIEW_SELECTED(sc, track))
1109                         has_selection = TRUE;
1110
1111                 track = track->next;
1112         }
1113
1114         if (!has_selection)
1115                 sc->flag &= ~SC_LOCK_SELECTION;
1116
1117         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, NULL);
1118
1119         return OPERATOR_FINISHED;
1120 }
1121
1122 void CLIP_OT_select_all(wmOperatorType *ot)
1123 {
1124         /* identifiers */
1125         ot->name = "(De)select All";
1126         ot->description = "Change selection of all tracking markers";
1127         ot->idname = "CLIP_OT_select_all";
1128
1129         /* api callbacks */
1130         ot->exec = select_all_exec;
1131         ot->poll = ED_space_clip_poll;
1132
1133         /* flags */
1134         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
1135
1136         WM_operator_properties_select_all(ot);
1137 }
1138
1139 /********************** select grouped operator *********************/
1140
1141 static int select_groped_exec(bContext *C, wmOperator *op)
1142 {
1143         SpaceClip *sc = CTX_wm_space_clip(C);
1144         MovieClip *clip = ED_space_clip(sc);
1145         MovieTrackingTrack *track;
1146         MovieTrackingMarker *marker;
1147         MovieTracking *tracking = &clip->tracking;
1148         ListBase *tracksbase = BKE_tracking_get_tracks(tracking);
1149         int group = RNA_enum_get(op->ptr, "group");
1150
1151         track = tracksbase->first;
1152         while (track) {
1153                 int ok = FALSE;
1154
1155                 marker = BKE_tracking_get_marker(track, sc->user.framenr);
1156
1157                 if (group == 0) { /* Keyframed */
1158                         ok = marker->framenr == sc->user.framenr && (marker->flag & MARKER_TRACKED)==0;
1159                 }
1160                 else if (group == 1) { /* Estimated */
1161                         ok = marker->framenr != sc->user.framenr;
1162                 }
1163                 else if (group == 2) { /* tracked */
1164                         ok = marker->framenr == sc->user.framenr && (marker->flag & MARKER_TRACKED);
1165                 }
1166                 else if (group == 3) { /* locked */
1167                         ok = track->flag & TRACK_LOCKED;
1168                 }
1169                 else if (group == 4) { /* disabled */
1170                         ok = marker->flag & MARKER_DISABLED;
1171                 }
1172                 else if (group == 5) { /* color */
1173                         MovieTrackingTrack *act_track = BKE_tracking_active_track(tracking);
1174
1175                         if (act_track) {
1176                                 ok = (track->flag & TRACK_CUSTOMCOLOR) == (act_track->flag & TRACK_CUSTOMCOLOR);
1177
1178                                 if (ok && track->flag & TRACK_CUSTOMCOLOR)
1179                                         ok = equals_v3v3(track->color, act_track->color);
1180                         }
1181                 }
1182                 else if (group == 6) { /* failed */
1183                         ok = (track->flag & TRACK_HAS_BUNDLE) == 0;
1184                 }
1185
1186                 if (ok) {
1187                         track->flag |= SELECT;
1188                         if (sc->flag & SC_SHOW_MARKER_PATTERN)
1189                                 track->pat_flag |= SELECT;
1190                         if (sc->flag & SC_SHOW_MARKER_SEARCH)
1191                                 track->search_flag |= SELECT;
1192                 }
1193
1194                 track = track->next;
1195         }
1196
1197         WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, clip);
1198
1199         return OPERATOR_FINISHED;
1200 }
1201
1202 void CLIP_OT_select_grouped(wmOperatorType *ot)
1203 {
1204         static EnumPropertyItem select_group_items[] = {
1205                         {0, "KEYFRAMED", 0, "Keyframed tracks", "Select all keyframed tracks"},
1206                         {1, "ESTIMATED", 0, "Estimated tracks", "Select all estimated tracks"},
1207                         {2, "TRACKED", 0, "Tracked tracks", "Select all tracked tracks"},
1208                         {3, "LOCKED", 0, "Locked tracks", "Select all locked tracks"},
1209                         {4, "DISABLED", 0, "Disabled tracks", "Select all disabled tracks"},
1210                         {5, "COLOR", 0, "Tracks with same color", "Select all tracks with same color as active track"},
1211                         {6, "FAILED", 0, "Failed Tracks", "Select all tracks which failed to be reconstructed"},
1212                         {0, NULL, 0, NULL, NULL}
1213         };
1214
1215         /* identifiers */
1216         ot->name = "Select Grouped";
1217         ot->description = "Select all tracks from specified group";
1218         ot->idname = "CLIP_OT_select_grouped";
1219
1220         /* api callbacks */
1221         ot->exec = select_groped_exec;
1222         ot->poll = space_clip_size_poll;
1223
1224         /* flags */
1225         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
1226
1227         /* proeprties */
1228         RNA_def_enum(ot->srna, "group", select_group_items, TRACK_CLEAR_REMAINED, "Action", "Clear action to execute");
1229 }
1230
1231 /********************** track operator *********************/
1232
1233 typedef struct TrackMarkersJob {
1234         struct MovieTrackingContext *context;   /* tracking context */
1235         int sfra, efra, lastfra;        /* Start, end and recently tracked frames */
1236         int backwards;                          /* Backwards tracking flag */
1237         MovieClip *clip;                        /* Clip which is tracking */
1238         float delay;                            /* Delay in milliseconds to allow tracking at fixed FPS */
1239
1240         struct Main *main;
1241         struct Scene *scene;
1242         struct bScreen *screen;
1243 } TrackMarkersJob;
1244
1245 static int track_markers_testbreak(void)
1246 {
1247         return G.afbreek;
1248 }
1249
1250 static int track_count_markers(SpaceClip *sc, MovieClip *clip)
1251 {
1252         int tot = 0;
1253         ListBase *tracksbase = BKE_tracking_get_tracks(&clip->tracking);
1254         MovieTrackingTrack *track;
1255         int framenr = sc->user.framenr;
1256
1257         track = tracksbase->first;
1258         while (track) {
1259                 if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) {
1260                         MovieTrackingMarker *marker = BKE_tracking_get_marker(track, framenr);
1261
1262                         if (!marker || (marker->flag & MARKER_DISABLED) == 0)
1263                                 tot++;
1264                 }
1265
1266                 track = track->next;
1267         }
1268
1269         return tot;
1270 }
1271
1272 static void clear_invisible_track_selection(SpaceClip *sc, MovieClip *clip)
1273 {
1274         ListBase *tracksbase = BKE_tracking_get_tracks(&clip->tracking);
1275         int hidden = 0;
1276
1277         if ((sc->flag & SC_SHOW_MARKER_PATTERN)==0)
1278                 hidden |= TRACK_AREA_PAT;
1279
1280         if ((sc->flag & SC_SHOW_MARKER_SEARCH)==0)
1281                 hidden |= TRACK_AREA_SEARCH;
1282
1283         if (hidden) {
1284                 MovieTrackingTrack *track = tracksbase->first;
1285
1286                 while (track) {
1287                         if ((track->flag & TRACK_HIDDEN) == 0)
1288                                 BKE_tracking_track_flag(track, hidden, SELECT, 1);
1289
1290                         track = track->next;
1291                 }
1292         }
1293 }
1294
1295 static void track_init_markers(SpaceClip *sc, MovieClip *clip, int *frames_limit_r)
1296 {
1297         ListBase *tracksbase = BKE_tracking_get_tracks(&clip->tracking);
1298         MovieTrackingTrack *track;
1299         int framenr = sc->user.framenr;
1300         int frames_limit = 0;
1301
1302         clear_invisible_track_selection(sc, clip);
1303
1304         track = tracksbase->first;
1305         while (track) {
1306                 if (TRACK_VIEW_SELECTED(sc, track)) {
1307                         if ((track->flag & TRACK_HIDDEN)==0 && (track->flag & TRACK_LOCKED)==0) {
1308                                 BKE_tracking_ensure_marker(track, framenr);
1309
1310                                 if (track->frames_limit) {
1311                                         if (frames_limit == 0)
1312                                                 frames_limit = track->frames_limit;
1313                                         else
1314                                                 frames_limit = MIN2(frames_limit, track->frames_limit);
1315                                 }
1316                         }
1317                 }
1318
1319                 track = track->next;
1320         }
1321
1322         *frames_limit_r = frames_limit;
1323 }
1324
1325 static int track_markers_check_direction(int backwards, int curfra, int efra)
1326 {
1327         if (backwards) {
1328                 if (curfra < efra)
1329                         return FALSE;
1330         }
1331         else {
1332                 if (curfra > efra)
1333                         return FALSE;
1334         }
1335
1336         return TRUE;
1337 }
1338
1339 static int track_markers_initjob(bContext *C, TrackMarkersJob *tmj, int backwards)
1340 {
1341         SpaceClip *sc = CTX_wm_space_clip(C);
1342         MovieClip *clip = ED_space_clip(sc);
1343         Scene *scene = CTX_data_scene(C);
1344         MovieTrackingSettings *settings = &clip->tracking.settings;
1345         int frames_limit;
1346
1347         track_init_markers(sc, clip, &frames_limit);
1348
1349         tmj->sfra = sc->user.framenr;
1350         tmj->clip = clip;
1351         tmj->backwards = backwards;
1352
1353         if (backwards)
1354                 tmj->efra = SFRA;
1355         else
1356                 tmj->efra = EFRA;
1357
1358         /* limit frames to be tracked by user setting */
1359         if (frames_limit) {
1360                 if (backwards)
1361                         tmj->efra = MAX2(tmj->efra, tmj->sfra - frames_limit);
1362                 else
1363                         tmj->efra = MIN2(tmj->efra, tmj->sfra + frames_limit);
1364         }
1365
1366         if (settings->speed != TRACKING_SPEED_FASTEST) {
1367                 tmj->delay = 1.0f / scene->r.frs_sec * 1000.0f;
1368
1369                 if (settings->speed == TRACKING_SPEED_HALF)
1370                         tmj->delay *= 2;
1371                 else if (settings->speed == TRACKING_SPEED_QUARTER)
1372                         tmj->delay *= 4;
1373                 else if (settings->speed == TRACKING_SPEED_DOUBLE)
1374                         tmj->delay /= 2;
1375         }
1376
1377         tmj->context = BKE_tracking_context_new(clip, &sc->user, backwards, 1);
1378
1379         clip->tracking_context = tmj->context;
1380
1381         tmj->lastfra = tmj->sfra;
1382
1383         /* XXX: silly to store this, but this data is needed to update scene and movie-clip
1384          *      frame numbers when tracking is finished. This introduces better feedback for artists.
1385          *      Maybe there's another way to solve this problem, but can't think better way atm.
1386          *      Anyway, this way isn't more unstable as animation rendering animation
1387          *      which uses the same approach (except storing screen). */
1388         tmj->scene = scene;
1389         tmj->main = CTX_data_main(C);
1390         tmj->screen = CTX_wm_screen(C);
1391
1392         return track_markers_check_direction(backwards, tmj->sfra, tmj->efra);
1393 }
1394
1395 static void track_markers_startjob(void *tmv, short *stop, short *do_update, float *progress)
1396 {
1397         TrackMarkersJob *tmj = (TrackMarkersJob *)tmv;
1398         int framenr = tmj->sfra;
1399         //double t = PIL_check_seconds_timer();
1400
1401         while (framenr != tmj->efra) {
1402                 if (tmj->delay > 0) {
1403                         /* tracking should happen with fixed fps. Calculate time
1404                          * using current timer value before tracking frame and after.
1405                          *
1406                          * Small (and maybe unneeded optimization): do not calculate exec_time
1407                          * for "Fastest" tracking */
1408
1409                         double start_time = PIL_check_seconds_timer(), exec_time;
1410
1411                         if (!BKE_tracking_next(tmj->context))
1412                                 break;
1413
1414                         exec_time = PIL_check_seconds_timer()-start_time;
1415                         if (tmj->delay > (float)exec_time)
1416                                 PIL_sleep_ms(tmj->delay-(float)exec_time);
1417                 }
1418                 else if (!BKE_tracking_next(tmj->context))
1419                                 break;
1420
1421                 *do_update = TRUE;
1422                 *progress = (float)(framenr-tmj->sfra) / (tmj->efra-tmj->sfra);
1423
1424                 if (tmj->backwards)
1425                         framenr--;
1426                 else
1427                         framenr++;
1428
1429                 tmj->lastfra = framenr;
1430
1431                 if (*stop || track_markers_testbreak())
1432                         break;
1433         }
1434
1435         //printf("Tracking time: %lf\n", PIL_check_seconds_timer()-t);
1436 }
1437
1438 static void track_markers_updatejob(void *tmv)
1439 {
1440         TrackMarkersJob *tmj = (TrackMarkersJob *)tmv;
1441
1442         BKE_tracking_sync(tmj->context);
1443 }
1444
1445 static void track_markers_freejob(void *tmv)
1446 {
1447         TrackMarkersJob *tmj = (TrackMarkersJob *)tmv;
1448
1449         tmj->clip->tracking_context = NULL;
1450         tmj->scene->r.cfra = tmj->lastfra;
1451         ED_update_for_newframe(tmj->main, tmj->scene, tmj->screen, 0);
1452
1453         BKE_tracking_sync(tmj->context);
1454         BKE_tracking_context_free(tmj->context);
1455
1456         MEM_freeN(tmj);
1457
1458         WM_main_add_notifier(NC_SCENE|ND_FRAME, tmj->scene);
1459 }
1460
1461 static int track_markers_exec(bContext *C, wmOperator *op)
1462 {
1463         SpaceClip *sc = CTX_wm_space_clip(C);
1464         MovieClip *clip = ED_space_clip(sc);
1465         Scene *scene = CTX_data_scene(C);
1466         struct MovieTrackingContext *context;
1467         int framenr = sc->user.framenr;
1468         int sfra = framenr, efra;
1469         int backwards = RNA_boolean_get(op->ptr, "backwards");
1470         int sequence = RNA_boolean_get(op->ptr, "sequence");
1471         int frames_limit;
1472
1473         if (track_count_markers(sc, clip)==0)
1474                 return OPERATOR_CANCELLED;
1475
1476         track_init_markers(sc, clip, &frames_limit);
1477
1478         if (backwards)
1479                 efra = SFRA;
1480         else
1481                 efra = EFRA;
1482
1483         /* limit frames to be tracked by user setting */
1484         if (frames_limit) {
1485                 if (backwards) efra = MAX2(efra, sfra-frames_limit);
1486                 else efra = MIN2(efra, sfra+frames_limit);
1487         }
1488
1489         if (!track_markers_check_direction(backwards, framenr, efra))
1490                 return OPERATOR_CANCELLED;
1491
1492         /* do not disable tracks due to threshold when tracking frame-by-frame */
1493         context = BKE_tracking_context_new(clip, &sc->user, backwards, sequence);
1494
1495         while (framenr != efra) {
1496                 if (!BKE_tracking_next(context))
1497                         break;
1498
1499                 if (backwards) framenr--;
1500                 else framenr++;
1501
1502                 if (!sequence)
1503                         break;
1504         }
1505
1506         BKE_tracking_sync(context);
1507         BKE_tracking_context_free(context);
1508
1509         /* update scene current frame to the lastes tracked frame */
1510         scene->r.cfra = framenr;
1511
1512         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
1513         WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
1514
1515         return OPERATOR_FINISHED;
1516 }
1517
1518 static int track_markers_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
1519 {
1520         TrackMarkersJob *tmj;
1521         ScrArea *sa = CTX_wm_area(C);
1522         SpaceClip *sc = CTX_wm_space_clip(C);
1523         MovieClip *clip = ED_space_clip(sc);
1524         wmJob *steve;
1525         int backwards = RNA_boolean_get(op->ptr, "backwards");
1526         int sequence = RNA_boolean_get(op->ptr, "sequence");
1527
1528         if (WM_jobs_test(CTX_wm_manager(C), CTX_wm_area(C))) {
1529                 /* only one tracking is allowed at a time */
1530                 return OPERATOR_CANCELLED;
1531         }
1532
1533         if (clip->tracking_context)
1534                 return OPERATOR_CANCELLED;
1535
1536         if (track_count_markers(sc, clip)==0)
1537                 return OPERATOR_CANCELLED;
1538
1539         if (!sequence)
1540                 return track_markers_exec(C, op);
1541
1542         tmj = MEM_callocN(sizeof(TrackMarkersJob), "TrackMarkersJob data");
1543         if (!track_markers_initjob(C, tmj, backwards)) {
1544                 track_markers_freejob(tmj);
1545
1546                 return OPERATOR_CANCELLED;
1547         }
1548
1549         /* setup job */
1550         steve = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), sa, "Track Markers", WM_JOB_PROGRESS);
1551         WM_jobs_customdata(steve, tmj, track_markers_freejob);
1552
1553         /* if there's delay set in tracking job, tracking should happen
1554          * with fixed FPS. To deal with editor refresh we have to synchronize
1555          * tracks from job and tracks in clip. Do this in timer callback
1556          * to prevent threading conflicts. */
1557         if (tmj->delay>0) WM_jobs_timer(steve, tmj->delay/1000.0f, NC_MOVIECLIP|NA_EVALUATED, 0);
1558         else WM_jobs_timer(steve, 0.2, NC_MOVIECLIP|NA_EVALUATED, 0);
1559
1560         WM_jobs_callbacks(steve, track_markers_startjob, NULL, track_markers_updatejob, NULL);
1561
1562         G.afbreek = 0;
1563
1564         WM_jobs_start(CTX_wm_manager(C), steve);
1565         WM_cursor_wait(0);
1566
1567         /* add modal handler for ESC */
1568         WM_event_add_modal_handler(C, op);
1569
1570         return OPERATOR_RUNNING_MODAL;
1571 }
1572
1573 static int track_markers_modal(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
1574 {
1575         /* no running tracking, remove handler and pass through */
1576         if (0==WM_jobs_test(CTX_wm_manager(C), CTX_wm_area(C)))
1577                 return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
1578
1579         /* running tracking */
1580         switch (event->type) {
1581                 case ESCKEY:
1582                         return OPERATOR_RUNNING_MODAL;
1583                         break;
1584         }
1585
1586         return OPERATOR_PASS_THROUGH;
1587 }
1588
1589 void CLIP_OT_track_markers(wmOperatorType *ot)
1590 {
1591         /* identifiers */
1592         ot->name = "Track Markers";
1593         ot->description = "Track selected markers";
1594         ot->idname = "CLIP_OT_track_markers";
1595
1596         /* api callbacks */
1597         ot->exec = track_markers_exec;
1598         ot->invoke = track_markers_invoke;
1599         ot->poll = space_clip_frame_poll;
1600         ot->modal = track_markers_modal;
1601
1602         /* flags */
1603         ot->flag = OPTYPE_UNDO;
1604
1605         /* properties */
1606         RNA_def_boolean(ot->srna, "backwards", 0, "Backwards", "Do backwards tracking");
1607         RNA_def_boolean(ot->srna, "sequence", 0, "Track Sequence", "Track marker during image sequence rather than single image");
1608 }
1609
1610 /********************** solve camera operator *********************/
1611
1612 typedef struct {
1613         Scene *scene;
1614         MovieClip *clip;
1615         MovieClipUser user;
1616
1617         ReportList *reports;
1618
1619         char stats_message[256];
1620
1621         struct MovieReconstructContext *context;
1622 } SolveCameraJob;
1623
1624 static int solve_camera_initjob(bContext *C, SolveCameraJob *scj, wmOperator *op, char *error_msg, int max_error)
1625 {
1626         SpaceClip *sc = CTX_wm_space_clip(C);
1627         MovieClip *clip = ED_space_clip(sc);
1628         Scene *scene = CTX_data_scene(C);
1629         MovieTracking *tracking = &clip->tracking;
1630         MovieTrackingSettings *settings = &clip->tracking.settings;
1631         MovieTrackingObject *object = BKE_tracking_active_object(tracking);
1632         int width, height;
1633
1634         if (!BKE_tracking_can_reconstruct(tracking, object, error_msg, max_error))
1635                 return 0;
1636
1637         /* could fail if footage uses images with different sizes */
1638         BKE_movieclip_get_size(clip, &sc->user, &width, &height);
1639
1640         scj->clip = clip;
1641         scj->scene = scene;
1642         scj->reports = op->reports;
1643         scj->user = sc->user;
1644
1645         scj->context = BKE_tracking_reconstruction_context_new(tracking, object,
1646                         settings->keyframe1, settings->keyframe2, width, height);
1647
1648         tracking->stats = MEM_callocN(sizeof(MovieTrackingStats), "solve camera stats");
1649
1650         return 1;
1651 }
1652
1653 static void solve_camera_updatejob(void *scv)
1654 {
1655         SolveCameraJob *scj = (SolveCameraJob *)scv;
1656         MovieTracking *tracking = &scj->clip->tracking;
1657
1658         BLI_strncpy(tracking->stats->message, scj->stats_message, sizeof(tracking->stats->message));
1659 }
1660
1661 static void solve_camera_startjob(void *scv, short *stop, short *do_update, float *progress)
1662 {
1663         SolveCameraJob *scj = (SolveCameraJob *)scv;
1664
1665         BKE_tracking_solve_reconstruction(scj->context, stop, do_update, progress,
1666                         scj->stats_message, sizeof(scj->stats_message));
1667 }
1668
1669 static void solve_camera_freejob(void *scv)
1670 {
1671         SolveCameraJob *scj = (SolveCameraJob *)scv;
1672         MovieTracking *tracking = &scj->clip->tracking;
1673         Scene *scene = scj->scene;
1674         MovieClip *clip = scj->clip;
1675         int solved;
1676
1677         if (!scj->context) {
1678                 /* job weren't fully initialized due to some error */
1679                 MEM_freeN(scj);
1680                 return;
1681         }
1682
1683         solved = BKE_tracking_finish_reconstruction(scj->context, tracking);
1684
1685         if (!solved)
1686                 BKE_report(scj->reports, RPT_WARNING, "Some data failed to reconstruct, see console for details");
1687         else
1688                 BKE_reportf(scj->reports, RPT_INFO, "Average re-projection error %.3f", tracking->reconstruction.error);
1689
1690         /* set currently solved clip as active for scene */
1691         if (scene->clip)
1692                 id_us_min(&clip->id);
1693
1694         scene->clip = clip;
1695         id_us_plus(&clip->id);
1696
1697         /* set blender camera focal length so result would look fine there */
1698         if (scene->camera) {
1699                 Camera *camera = (Camera*)scene->camera->data;
1700                 int width, height;
1701
1702                 BKE_movieclip_get_size(clip, &scj->user, &width, &height);
1703
1704                 BKE_tracking_camera_to_blender(tracking, scene, camera, width, height);
1705
1706                 WM_main_add_notifier(NC_OBJECT, camera);
1707         }
1708
1709         MEM_freeN(tracking->stats);
1710         tracking->stats = NULL;
1711
1712         DAG_id_tag_update(&clip->id, 0);
1713
1714         WM_main_add_notifier(NC_MOVIECLIP|NA_EVALUATED, clip);
1715         WM_main_add_notifier(NC_OBJECT|ND_TRANSFORM, NULL);
1716
1717         /* update active clip displayed in scene buttons */
1718         WM_main_add_notifier(NC_SCENE, scene);
1719
1720         BKE_tracking_reconstruction_context_free(scj->context);
1721         MEM_freeN(scj);
1722 }
1723
1724 static int solve_camera_exec(bContext *C, wmOperator *op)
1725 {
1726         SolveCameraJob *scj;
1727         char error_msg[256] = "\0";
1728
1729         scj = MEM_callocN(sizeof(SolveCameraJob), "SolveCameraJob data");
1730         if (!solve_camera_initjob(C, scj, op, error_msg, sizeof(error_msg))) {
1731                 if (error_msg[0])
1732                         BKE_report(op->reports, RPT_ERROR, error_msg);
1733
1734                 solve_camera_freejob(scj);
1735
1736                 return OPERATOR_CANCELLED;
1737         }
1738
1739         solve_camera_startjob(scj, NULL, NULL, NULL);
1740
1741         solve_camera_freejob(scj);
1742
1743         return OPERATOR_FINISHED;
1744 }
1745
1746 static int solve_camera_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
1747 {
1748         SolveCameraJob *scj;
1749         ScrArea *sa = CTX_wm_area(C);
1750         SpaceClip *sc = CTX_wm_space_clip(C);
1751         MovieClip *clip = ED_space_clip(sc);
1752         MovieTracking *tracking = &clip->tracking;
1753         MovieTrackingReconstruction *reconstruction = BKE_tracking_get_reconstruction(tracking);
1754         wmJob *steve;
1755         char error_msg[256] = "\0";
1756
1757         if (WM_jobs_test(CTX_wm_manager(C), CTX_wm_area(C))) {
1758                 /* only one solve is allowed at a time */
1759                 return OPERATOR_CANCELLED;
1760         }
1761
1762         scj = MEM_callocN(sizeof(SolveCameraJob), "SolveCameraJob data");
1763         if (!solve_camera_initjob(C, scj, op, error_msg, sizeof(error_msg))) {
1764                 if (error_msg[0])
1765                         BKE_report(op->reports, RPT_ERROR, error_msg);
1766
1767                 solve_camera_freejob(scj);
1768
1769                 return OPERATOR_CANCELLED;
1770         }
1771
1772         BLI_strncpy(tracking->stats->message, "Solving camera | Preparing solve", sizeof(tracking->stats->message));
1773
1774         /* hide reconstruction statistics from previous solve */
1775         reconstruction->flag &= ~TRACKING_RECONSTRUCTED;
1776         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
1777
1778         /* setup job */
1779         steve = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), sa, "Solve Camera", WM_JOB_PROGRESS);
1780         WM_jobs_customdata(steve, scj, solve_camera_freejob);
1781         WM_jobs_timer(steve, 0.1, NC_MOVIECLIP|NA_EVALUATED, 0);
1782         WM_jobs_callbacks(steve, solve_camera_startjob, NULL, solve_camera_updatejob, NULL);
1783
1784         G.afbreek = 0;
1785
1786         WM_jobs_start(CTX_wm_manager(C), steve);
1787         WM_cursor_wait(0);
1788
1789         /* add modal handler for ESC */
1790         WM_event_add_modal_handler(C, op);
1791
1792         return OPERATOR_RUNNING_MODAL;
1793 }
1794
1795 static int solve_camera_modal(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
1796 {
1797         /* no running solver, remove handler and pass through */
1798         if (0 == WM_jobs_test(CTX_wm_manager(C), CTX_wm_area(C)))
1799                 return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
1800
1801         /* running tracking */
1802         switch (event->type) {
1803                 case ESCKEY:
1804                         return OPERATOR_RUNNING_MODAL;
1805                         break;
1806         }
1807
1808         return OPERATOR_PASS_THROUGH;
1809 }
1810
1811 void CLIP_OT_solve_camera(wmOperatorType *ot)
1812 {
1813         /* identifiers */
1814         ot->name = "Solve Camera";
1815         ot->description = "Solve camera motion from tracks";
1816         ot->idname = "CLIP_OT_solve_camera";
1817
1818         /* api callbacks */
1819         ot->exec = solve_camera_exec;
1820         ot->invoke = solve_camera_invoke;
1821         ot->modal = solve_camera_modal;
1822         ot->poll = ED_space_clip_poll;
1823
1824         /* flags */
1825         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
1826 }
1827
1828 /********************** clear solution operator *********************/
1829
1830 static int clear_solution_exec(bContext *C, wmOperator *UNUSED(op))
1831 {
1832         SpaceClip *sc = CTX_wm_space_clip(C);
1833         MovieClip *clip = ED_space_clip(sc);
1834         MovieTracking *tracking = &clip->tracking;
1835         ListBase *tracksbase = BKE_tracking_get_tracks(&clip->tracking);
1836         MovieTrackingReconstruction *reconstruction = BKE_tracking_get_reconstruction(tracking);
1837         MovieTrackingTrack *track = tracksbase->first;
1838
1839         while (track) {
1840                 track->flag &= ~TRACK_HAS_BUNDLE;
1841
1842                 track = track->next;
1843         }
1844
1845         if (reconstruction->cameras)
1846                 MEM_freeN(reconstruction->cameras);
1847
1848         reconstruction->cameras = NULL;
1849         reconstruction->camnr = 0;
1850
1851         reconstruction->flag &= ~TRACKING_RECONSTRUCTED;
1852
1853         DAG_id_tag_update(&clip->id, 0);
1854
1855         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
1856         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, NULL);
1857
1858         return OPERATOR_FINISHED;
1859 }
1860
1861 void CLIP_OT_clear_solution(wmOperatorType *ot)
1862 {
1863         /* identifiers */
1864         ot->name = "Clear Solution";
1865         ot->description = "Clear all calculated data";
1866         ot->idname = "CLIP_OT_clear_solution";
1867
1868         /* api callbacks */
1869         ot->exec = clear_solution_exec;
1870         ot->poll = ED_space_clip_poll;
1871
1872         /* flags */
1873         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
1874 }
1875
1876 /********************** clear track operator *********************/
1877
1878 static int clear_track_path_exec(bContext *C, wmOperator *op)
1879 {
1880         SpaceClip *sc = CTX_wm_space_clip(C);
1881         MovieClip *clip = ED_space_clip(sc);
1882         MovieTrackingTrack *track;
1883         ListBase *tracksbase = BKE_tracking_get_tracks(&clip->tracking);
1884         int action = RNA_enum_get(op->ptr, "action");
1885         int clear_active = RNA_boolean_get(op->ptr, "clear_active");
1886
1887         if (clear_active) {
1888                 track = BKE_tracking_active_track(&clip->tracking);
1889                 BKE_tracking_clear_path(track, sc->user.framenr, action);
1890         }
1891         else {
1892                 track = tracksbase->first;
1893                 while (track) {
1894                         if (TRACK_VIEW_SELECTED(sc, track))
1895                                 BKE_tracking_clear_path(track, sc->user.framenr, action);
1896
1897                         track = track->next;
1898                 }
1899         }
1900
1901         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
1902
1903         return OPERATOR_FINISHED;
1904 }
1905
1906 void CLIP_OT_clear_track_path(wmOperatorType *ot)
1907 {
1908         static EnumPropertyItem clear_path_actions[] = {
1909                         {TRACK_CLEAR_UPTO, "UPTO", 0, "Clear up-to", "Clear path up to current frame"},
1910                         {TRACK_CLEAR_REMAINED, "REMAINED", 0, "Clear remained", "Clear path at remaining frames (after current)"},
1911                         {TRACK_CLEAR_ALL, "ALL", 0, "Clear all", "Clear the whole path"},
1912                         {0, NULL, 0, NULL, NULL}
1913         };
1914
1915         /* identifiers */
1916         ot->name = "Clear Track Path";
1917         ot->description = "Clear tracks after/before current position or clear the whole track";
1918         ot->idname = "CLIP_OT_clear_track_path";
1919
1920         /* api callbacks */
1921         ot->exec = clear_track_path_exec;
1922         ot->poll = ED_space_clip_poll;
1923
1924         /* flags */
1925         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
1926
1927         /* proeprties */
1928         RNA_def_enum(ot->srna, "action", clear_path_actions, TRACK_CLEAR_REMAINED, "Action", "Clear action to execute");
1929         RNA_def_boolean(ot->srna, "clear_active", 0, "Clear Active", "Clear active track only instead of all selected tracks");
1930 }
1931
1932 /********************** disable markers operator *********************/
1933
1934 static int disable_markers_exec(bContext *C, wmOperator *op)
1935 {
1936         SpaceClip *sc = CTX_wm_space_clip(C);
1937         MovieClip *clip = ED_space_clip(sc);
1938         MovieTracking *tracking = &clip->tracking;
1939         ListBase *tracksbase = BKE_tracking_get_tracks(tracking);
1940         MovieTrackingTrack *track = tracksbase->first;
1941         int action = RNA_enum_get(op->ptr, "action");
1942
1943         while (track) {
1944                 if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED)==0) {
1945                         MovieTrackingMarker *marker = BKE_tracking_ensure_marker(track, sc->user.framenr);
1946
1947                         if (action == 0)
1948                                 marker->flag |= MARKER_DISABLED;
1949                         else if (action == 1)
1950                                 marker->flag &= ~MARKER_DISABLED;
1951                         else marker->flag ^= MARKER_DISABLED;
1952                 }
1953
1954                 track = track->next;
1955         }
1956
1957         DAG_id_tag_update(&clip->id, 0);
1958
1959         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
1960
1961         return OPERATOR_FINISHED;
1962 }
1963
1964 void CLIP_OT_disable_markers(wmOperatorType *ot)
1965 {
1966         static EnumPropertyItem actions_items[] = {
1967                         {0, "DISABLE", 0, "Disable", "Disable selected markers"},
1968                         {1, "ENABLE", 0, "Enable", "Enable selected markers"},
1969                         {2, "TOGGLE", 0, "Toggle", "Toggle disabled flag for selected markers"},
1970                         {0, NULL, 0, NULL, NULL}
1971         };
1972
1973         /* identifiers */
1974         ot->name = "Disable Markers";
1975         ot->description = "Disable/enable selected markers";
1976         ot->idname = "CLIP_OT_disable_markers";
1977
1978         /* api callbacks */
1979         ot->exec = disable_markers_exec;
1980         ot->poll = ED_space_clip_poll;
1981
1982         /* flags */
1983         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
1984
1985         /* properties */
1986         RNA_def_enum(ot->srna, "action", actions_items, 0, "Action", "Disable action to execute");
1987 }
1988
1989 /********************** set origin operator *********************/
1990
1991 static Object *get_camera_with_movieclip(Scene *scene, MovieClip *clip)
1992 {
1993         Object *camera = scene->camera;
1994         Base *base;
1995
1996         if (camera && object_get_movieclip(scene, camera, 0)==clip)
1997                 return camera;
1998
1999         base = scene->base.first;
2000         while (base) {
2001                 if (base->object->type == OB_CAMERA) {
2002                         if (object_get_movieclip(scene, base->object, 0)==clip) {
2003                                 camera = base->object;
2004                                 break;
2005                         }
2006                 }
2007
2008                 base = base->next;
2009         }
2010
2011         return camera;
2012 }
2013
2014 static Object *get_orientation_object(bContext *C)
2015 {
2016         Scene *scene = CTX_data_scene(C);
2017         SpaceClip *sc = CTX_wm_space_clip(C);
2018         MovieClip *clip = ED_space_clip(sc);
2019         MovieTracking *tracking = &clip->tracking;
2020         MovieTrackingObject *tracking_object = BKE_tracking_active_object(tracking);
2021         Object *object = NULL;
2022
2023         if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
2024                 object = get_camera_with_movieclip(scene, clip);
2025         }
2026         else {
2027                 object = OBACT;
2028         }
2029
2030         if (object && object->parent)
2031                 object = object->parent;
2032
2033         return object;
2034 }
2035
2036 static int set_orientation_poll(bContext *C)
2037 {
2038         if (space_clip_size_poll(C)) {
2039                 Scene *scene = CTX_data_scene(C);
2040                 SpaceClip *sc = CTX_wm_space_clip(C);
2041                 MovieClip *clip = ED_space_clip(sc);
2042                 MovieTracking *tracking = &clip->tracking;
2043                 MovieTrackingObject *tracking_object = BKE_tracking_active_object(tracking);
2044
2045                 if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
2046                         return TRUE;
2047                 }
2048                 else {
2049                         return OBACT != NULL;
2050                 }
2051         }
2052
2053         return FALSE;
2054 }
2055
2056 static int count_selected_bundles(bContext *C)
2057 {
2058         SpaceClip *sc = CTX_wm_space_clip(C);
2059         MovieClip *clip = ED_space_clip(sc);
2060         ListBase *tracksbase = BKE_tracking_get_tracks(&clip->tracking);
2061         MovieTrackingTrack *track;
2062         int tot = 0;
2063
2064         track = tracksbase->first;
2065         while (track) {
2066                 if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_HAS_BUNDLE))
2067                         tot++;
2068
2069                 track = track->next;
2070         }
2071
2072         return tot;
2073 }
2074
2075 static void object_solver_inverted_matrix(Scene *scene, Object *ob, float invmat[4][4])
2076 {
2077         bConstraint *con;
2078         int found = FALSE;
2079
2080         for (con = ob->constraints.first; con; con = con->next) {
2081                 bConstraintTypeInfo *cti = constraint_get_typeinfo(con);
2082
2083                 if (!cti)
2084                         continue;
2085
2086                 if (cti->type == CONSTRAINT_TYPE_OBJECTSOLVER) {
2087                         bObjectSolverConstraint *data = (bObjectSolverConstraint *)con->data;
2088
2089                         if (!found) {
2090                                 Object *cam = data->camera ? data->camera : scene->camera;
2091
2092                                 where_is_object_mat(scene, cam, invmat);
2093                         }
2094
2095                         mult_m4_m4m4(invmat, invmat, data->invmat);
2096
2097                         found = TRUE;
2098                 }
2099         }
2100
2101         if (found)
2102                 invert_m4(invmat);
2103         else
2104                 unit_m4(invmat);
2105 }
2106
2107 static Object *object_solver_camera(Scene *scene, Object *ob)
2108 {
2109         bConstraint *con;
2110
2111         for (con = ob->constraints.first; con; con = con->next) {
2112                 bConstraintTypeInfo *cti = constraint_get_typeinfo(con);
2113
2114                 if (!cti)
2115                         continue;
2116
2117                 if (cti->type == CONSTRAINT_TYPE_OBJECTSOLVER) {
2118                         bObjectSolverConstraint *data = (bObjectSolverConstraint *)con->data;
2119
2120                         return data->camera ? data->camera : scene->camera;
2121                 }
2122         }
2123
2124         return NULL;
2125 }
2126
2127 static int set_origin_exec(bContext *C, wmOperator *op)
2128 {
2129         SpaceClip *sc = CTX_wm_space_clip(C);
2130         MovieClip *clip = ED_space_clip(sc);
2131         MovieTracking *tracking = &clip->tracking;
2132         MovieTrackingTrack *track;
2133         MovieTrackingObject *tracking_object;
2134         Scene *scene = CTX_data_scene(C);
2135         Object *object;
2136         Object *camera = get_camera_with_movieclip(scene, clip);
2137         ListBase *tracksbase;
2138         float mat[4][4], vec[3], median[3];
2139         int selected_count = count_selected_bundles(C);
2140
2141         if (selected_count == 0) {
2142                 BKE_report(op->reports, RPT_ERROR, "At least one track with bundle should be selected to define origin position");
2143
2144                 return OPERATOR_CANCELLED;
2145         }
2146
2147         object = get_orientation_object(C);
2148         if (!object) {
2149                 BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
2150
2151                 return OPERATOR_CANCELLED;
2152         }
2153
2154         tracking_object = BKE_tracking_active_object(tracking);
2155
2156         tracksbase = BKE_tracking_object_tracks(tracking, tracking_object);
2157
2158         track = tracksbase->first;
2159         zero_v3(median);
2160         while (track) {
2161                 if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_HAS_BUNDLE)) {
2162                         add_v3_v3(median, track->bundle_pos);
2163                 }
2164
2165                 track = track->next;
2166         }
2167         mul_v3_fl(median, 1.0f/selected_count);
2168
2169         BKE_get_tracking_mat(scene, camera, mat);
2170
2171         mul_v3_m4v3(vec, mat, median);
2172
2173         if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
2174                 sub_v3_v3(object->loc, vec);
2175         }
2176         else {
2177                 object_solver_inverted_matrix(scene, object, mat);
2178                 mul_v3_m4v3(vec, mat, vec);
2179                 copy_v3_v3(object->loc, vec);
2180         }
2181
2182         DAG_id_tag_update(&clip->id, 0);
2183         DAG_id_tag_update(&object->id, OB_RECALC_OB);
2184
2185         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
2186         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
2187
2188         return OPERATOR_FINISHED;
2189 }
2190
2191 void CLIP_OT_set_origin(wmOperatorType *ot)
2192 {
2193         /* identifiers */
2194         ot->name = "Set Origin";
2195         ot->description = "Set active marker as origin by moving camera (or it's parent if present) in 3D space";
2196         ot->idname = "CLIP_OT_set_origin";
2197
2198         /* api callbacks */
2199         ot->exec = set_origin_exec;
2200         ot->poll = set_orientation_poll;
2201
2202         /* flags */
2203         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
2204
2205         /* properties */
2206         RNA_def_boolean(ot->srna, "use_median", 0, "Use Median", "Set origin to median point of selected bundles");
2207 }
2208
2209 /********************** set floor operator *********************/
2210
2211 static void set_axis(Scene *scene,  Object *ob, MovieClip *clip, MovieTrackingObject *tracking_object,
2212                         MovieTrackingTrack *track, char axis)
2213 {
2214         Object *camera = get_camera_with_movieclip(scene, clip);
2215         int is_camera = tracking_object->flag & TRACKING_OBJECT_CAMERA;
2216         int  flip = FALSE;
2217         float mat[4][4], vec[3], obmat[4][4], dvec[3];
2218
2219         object_to_mat4(ob, obmat);
2220
2221         BKE_get_tracking_mat(scene, camera, mat);
2222         mul_v3_m4v3(vec, mat, track->bundle_pos);
2223         copy_v3_v3(dvec, vec);
2224
2225         if (!is_camera) {
2226                 float imat[4][4];
2227
2228                 object_solver_inverted_matrix(scene, ob, imat);
2229                 mul_v3_m4v3(vec, imat, vec);
2230
2231                 invert_m4_m4(imat, obmat);
2232                 mul_v3_m4v3(dvec, imat, vec);
2233
2234                 sub_v3_v3(vec, obmat[3]);
2235         }
2236
2237         if (len_v2(vec) < 1e-3f)
2238                 return;
2239
2240         unit_m4(mat);
2241
2242         if (axis == 'X') {
2243                 if (fabsf(dvec[1]) < 1e-3f) {
2244                         flip = TRUE;
2245
2246                         mat[0][0] = -1.0f; mat[0][1] = 0.0f; mat[0][2] = 0.0f;
2247                         mat[1][0] = 0.0f; mat[1][1] = -1.0f; mat[1][2] = 0.0f;
2248                         mat[2][0] = 0.0f; mat[2][1] = 0.0f; mat[2][2] = 1.0f;
2249                 }
2250                 else {
2251                         copy_v3_v3(mat[0], vec);
2252
2253                         if (is_camera || fabsf(vec[2]) < 1e-3f) {
2254                                 mat[0][2] = 0.0f;
2255                                 mat[2][0] = 0.0f; mat[2][1] = 0.0f; mat[2][2] = 1.0f;
2256                                 cross_v3_v3v3(mat[1], mat[2], mat[0]);
2257                         }
2258                         else {
2259                                 vec[2] = 0.0f;
2260
2261                                 cross_v3_v3v3(mat[1], mat[0], vec);
2262                                 cross_v3_v3v3(mat[2], mat[0], mat[1]);
2263                         }
2264                 }
2265         }
2266         else {
2267                 if (fabsf(dvec[0]) < 1e-3f) {
2268                         flip = TRUE;
2269
2270                         mat[0][0] = -1.0f; mat[0][1] = 0.0f; mat[0][2] = 0.0f;
2271                         mat[1][0] = 0.0f; mat[1][1] = -1.0f; mat[1][2] = 0.0f;
2272                         mat[2][0] = 0.0f; mat[2][1] = 0.0f; mat[2][2] = 1.0f;
2273                 }
2274                 else {
2275                         copy_v3_v3(mat[1], vec);
2276
2277                         if (is_camera || fabsf(vec[2])<1e-3f) {
2278                                 mat[1][2] = 0.0f;
2279                                 mat[2][0] = 0.0f; mat[2][1] = 0.0f; mat[2][2] = 1.0f;
2280                                 cross_v3_v3v3(mat[0], mat[1], mat[2]);
2281                         }
2282                         else {
2283                                 vec[2] = 0.0f;
2284
2285                                 cross_v3_v3v3(mat[0], vec, mat[1]);
2286                                 cross_v3_v3v3(mat[2], mat[0], mat[1]);
2287                         }
2288                 }
2289         }
2290
2291         normalize_v3(mat[0]);
2292         normalize_v3(mat[1]);
2293         normalize_v3(mat[2]);
2294
2295         if (is_camera) {
2296                 invert_m4(mat);
2297
2298                 mult_m4_m4m4(mat, mat, obmat);
2299         }
2300         else {
2301                 if (!flip) {
2302                         float lmat[4][4], ilmat[4][4], rmat[3][3];
2303
2304                         object_rot_to_mat3(ob, rmat);
2305                         invert_m3(rmat);
2306                         mul_m4_m4m3(mat, mat, rmat);
2307
2308                         unit_m4(lmat);
2309                         copy_v3_v3(lmat[3], obmat[3]);
2310                         invert_m4_m4(ilmat, lmat);
2311
2312                         mul_serie_m4(mat, lmat, mat, ilmat, obmat, NULL, NULL, NULL, NULL);
2313                 }
2314                 else {
2315                         mult_m4_m4m4(mat, obmat, mat);
2316                 }
2317         }
2318
2319         object_apply_mat4(ob, mat, 0, 0);
2320 }
2321
2322 static int set_plane_exec(bContext *C, wmOperator *op)
2323 {
2324         SpaceClip *sc = CTX_wm_space_clip(C);
2325         MovieClip *clip = ED_space_clip(sc);
2326         Scene *scene = CTX_data_scene(C);
2327         MovieTracking *tracking = &clip->tracking;
2328         MovieTrackingObject *tracking_object;
2329         MovieTrackingTrack *track, *axis_track = NULL, *act_track;
2330         ListBase *tracksbase;
2331         Object *object;
2332         Object *camera = get_camera_with_movieclip(scene, clip);
2333         int tot = 0;
2334         float vec[3][3], mat[4][4], obmat[4][4], newmat[4][4], orig[3] = {0.0f, 0.0f, 0.0f};
2335         int plane = RNA_enum_get(op->ptr, "plane");
2336         float rot[4][4] = {{0.0f, 0.0f, -1.0f, 0.0f},
2337                            {0.0f, 1.0f, 0.0f, 0.0f},
2338                            {1.0f, 0.0f, 0.0f, 0.0f},
2339                            {0.0f, 0.0f, 0.0f, 1.0f}};   /* 90 degrees Y-axis rotation matrix */
2340
2341         if (count_selected_bundles(C)!=3) {
2342                 BKE_report(op->reports, RPT_ERROR, "Three tracks with bundles are needed to orient the floor");
2343
2344                 return OPERATOR_CANCELLED;
2345         }
2346
2347         tracking_object = BKE_tracking_active_object(tracking);
2348         tracksbase = BKE_tracking_object_tracks(tracking, tracking_object);
2349         act_track = BKE_tracking_active_track(tracking);
2350
2351         object = get_orientation_object(C);
2352         if (!object) {
2353                 BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
2354
2355                 return OPERATOR_CANCELLED;
2356         }
2357
2358         BKE_get_tracking_mat(scene, camera, mat);
2359
2360         /* get 3 bundles to use as reference */
2361         track = tracksbase->first;
2362         while (track && tot<3) {
2363                 if (track->flag & TRACK_HAS_BUNDLE && TRACK_VIEW_SELECTED(sc, track)) {
2364                         mul_v3_m4v3(vec[tot], mat, track->bundle_pos);
2365
2366                         if (tot == 0 || track == act_track)
2367                                 copy_v3_v3(orig, vec[tot]);
2368                         else
2369                                 axis_track = track;
2370
2371                         tot++;
2372                 }
2373
2374                 track = track->next;
2375         }
2376
2377         sub_v3_v3(vec[1], vec[0]);
2378         sub_v3_v3(vec[2], vec[0]);
2379
2380         /* construct ortho-normal basis */
2381         unit_m4(mat);
2382
2383         if (plane == 0) { /* floor */
2384                 cross_v3_v3v3(mat[0], vec[1], vec[2]);
2385                 copy_v3_v3(mat[1], vec[1]);
2386                 cross_v3_v3v3(mat[2], mat[0], mat[1]);
2387         }
2388         else if (plane == 1) { /* wall */
2389                 cross_v3_v3v3(mat[2], vec[1], vec[2]);
2390                 copy_v3_v3(mat[1], vec[1]);
2391                 cross_v3_v3v3(mat[0], mat[1], mat[2]);
2392         }
2393
2394         normalize_v3(mat[0]);
2395         normalize_v3(mat[1]);
2396         normalize_v3(mat[2]);
2397
2398         /* move to origin point */
2399         mat[3][0] = orig[0];
2400         mat[3][1] = orig[1];
2401         mat[3][2] = orig[2];
2402
2403         if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
2404                 invert_m4(mat);
2405
2406                 object_to_mat4(object, obmat);
2407                 mult_m4_m4m4(mat, mat, obmat);
2408                 mult_m4_m4m4(newmat, rot, mat);
2409                 object_apply_mat4(object, newmat, 0, 0);
2410
2411                 /* make camera have positive z-coordinate */
2412                 if (object->loc[2]<0) {
2413                         invert_m4(rot);
2414                         mult_m4_m4m4(newmat, rot, mat);
2415                         object_apply_mat4(object, newmat, 0, 0);
2416                 }
2417         }
2418         else {
2419                 object_apply_mat4(object, mat, 0, 0);
2420         }
2421
2422         where_is_object(scene, object);
2423         set_axis(scene, object, clip, tracking_object, axis_track, 'X');
2424
2425         DAG_id_tag_update(&clip->id, 0);
2426         DAG_id_tag_update(&object->id, OB_RECALC_OB);
2427
2428         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
2429         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
2430
2431         return OPERATOR_FINISHED;
2432 }
2433
2434 void CLIP_OT_set_plane(wmOperatorType *ot)
2435 {
2436         static EnumPropertyItem plane_items[] = {
2437                         {0, "FLOOR", 0, "Floor", "Set floor plane"},
2438                         {1, "WALL", 0, "Wall", "Set wall plane"},
2439                         {0, NULL, 0, NULL, NULL}
2440         };
2441
2442         /* identifiers */
2443         ot->name = "Set Plane";
2444         ot->description = "Set plane based on 3 selected bundles by moving camera (or it's parent if present) in 3D space";
2445         ot->idname = "CLIP_OT_set_plane";
2446
2447         /* api callbacks */
2448         ot->exec = set_plane_exec;
2449         ot->poll = set_orientation_poll;
2450
2451         /* flags */
2452         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
2453
2454         /* properties */
2455         RNA_def_enum(ot->srna, "plane", plane_items, 0, "Plane", "Plane to be sued for orientation");
2456 }
2457
2458 /********************** set axis operator *********************/
2459
2460 static int set_axis_exec(bContext *C, wmOperator *op)
2461 {
2462         SpaceClip *sc = CTX_wm_space_clip(C);
2463         MovieClip *clip = ED_space_clip(sc);
2464         MovieTracking *tracking = &clip->tracking;
2465         MovieTrackingObject *tracking_object = BKE_tracking_active_object(tracking);
2466         MovieTrackingTrack *track;
2467         Scene *scene = CTX_data_scene(C);
2468         Object *object;
2469         ListBase *tracksbase;
2470         int axis = RNA_enum_get(op->ptr, "axis");
2471
2472         if (count_selected_bundles(C)!=1) {
2473                 BKE_report(op->reports, RPT_ERROR, "Single track with bundle should be selected to define axis");
2474
2475                 return OPERATOR_CANCELLED;
2476         }
2477
2478         object = get_orientation_object(C);
2479         if (!object) {
2480                 BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
2481
2482                 return OPERATOR_CANCELLED;
2483         }
2484
2485         tracksbase = BKE_tracking_object_tracks(tracking, tracking_object);
2486
2487         track = tracksbase->first;
2488         while (track) {
2489                 if (TRACK_VIEW_SELECTED(sc, track))
2490                         break;
2491
2492                 track = track->next;
2493         }
2494
2495         set_axis(scene, object, clip, tracking_object, track, axis == 0 ? 'X' : 'Y');
2496
2497         DAG_id_tag_update(&clip->id, 0);
2498         DAG_id_tag_update(&object->id, OB_RECALC_OB);
2499
2500         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
2501         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
2502
2503         return OPERATOR_FINISHED;
2504 }
2505
2506 void CLIP_OT_set_axis(wmOperatorType *ot)
2507 {
2508         static EnumPropertyItem axis_actions[] = {
2509                         {0, "X", 0, "X", "Align bundle align X axis"},
2510                         {1, "Y", 0, "Y", "Align bundle align Y axis"},
2511                         {0, NULL, 0, NULL, NULL}
2512         };
2513
2514         /* identifiers */
2515         ot->name = "Set Axis";
2516         ot->description = "Set direction of scene axis rotating camera (or it's parent if present) and assuming selected track lies on real axis joining it with the origin";
2517         ot->idname = "CLIP_OT_set_axis";
2518
2519         /* api callbacks */
2520         ot->exec = set_axis_exec;
2521         ot->poll = set_orientation_poll;
2522
2523         /* flags */
2524         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
2525
2526         /* properties */
2527         RNA_def_enum(ot->srna, "axis", axis_actions, 0, "Axis", "Axis to use to align bundle along");
2528 }
2529
2530 /********************** set scale operator *********************/
2531
2532 static int do_set_scale(bContext *C, wmOperator *op, int scale_solution)
2533 {
2534         SpaceClip *sc = CTX_wm_space_clip(C);
2535         MovieClip *clip = ED_space_clip(sc);
2536         MovieTracking *tracking = &clip->tracking;
2537         MovieTrackingObject *tracking_object = BKE_tracking_active_object(tracking);
2538         MovieTrackingTrack *track;
2539         Scene *scene = CTX_data_scene(C);
2540         Object *object = NULL;
2541         Object *camera = get_camera_with_movieclip(scene, clip);
2542         ListBase *tracksbase = BKE_tracking_get_tracks(tracking);
2543         int tot = 0;
2544         float vec[2][3], mat[4][4], scale;
2545         float dist = RNA_float_get(op->ptr, "distance");
2546
2547         if (count_selected_bundles(C) != 2) {
2548                 BKE_report(op->reports, RPT_ERROR, "Two tracks with bundles should be selected to set scale");
2549
2550                 return OPERATOR_CANCELLED;
2551         }
2552
2553         object = get_orientation_object(C);
2554         if (!object) {
2555                 BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
2556
2557                 return OPERATOR_CANCELLED;
2558         }
2559
2560         BKE_get_tracking_mat(scene, camera, mat);
2561
2562         track = tracksbase->first;
2563         while (track) {
2564                 if (TRACK_VIEW_SELECTED(sc, track)) {
2565                         mul_v3_m4v3(vec[tot], mat, track->bundle_pos);
2566                         tot++;
2567                 }
2568
2569                 track = track->next;
2570         }
2571
2572         sub_v3_v3(vec[0], vec[1]);
2573
2574         if (len_v3(vec[0])>1e-5f) {
2575                 scale = dist / len_v3(vec[0]);
2576
2577                 if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
2578                         mul_v3_fl(object->size, scale);
2579                         mul_v3_fl(object->loc, scale);
2580                 }
2581                 else if (!scale_solution) {
2582                         Object *solver_camera = object_solver_camera(scene, object);
2583
2584                         object->size[0] = object->size[1] = object->size[2] = 1.0f/scale;
2585
2586                         if (solver_camera) {
2587                                 object->size[0] /= solver_camera->size[0];
2588                                 object->size[1] /= solver_camera->size[1];
2589                                 object->size[2] /= solver_camera->size[2];
2590                         }
2591                 }
2592                 else {
2593                         tracking_object->scale = scale;
2594                 }
2595
2596                 DAG_id_tag_update(&clip->id, 0);
2597
2598                 if (object)
2599                         DAG_id_tag_update(&object->id, OB_RECALC_OB);
2600
2601                 WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
2602                 WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
2603         }
2604
2605         return OPERATOR_FINISHED;
2606 }
2607
2608 static int set_scale_exec(bContext *C, wmOperator *op)
2609 {
2610         return do_set_scale(C, op, 0);
2611 }
2612
2613 static int set_scale_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
2614 {
2615         SpaceClip *sc = CTX_wm_space_clip(C);
2616         MovieClip *clip = ED_space_clip(sc);
2617
2618         if (!RNA_struct_property_is_set(op->ptr, "distance"))
2619                 RNA_float_set(op->ptr, "distance", clip->tracking.settings.dist);
2620
2621         return set_scale_exec(C, op);
2622 }
2623
2624 void CLIP_OT_set_scale(wmOperatorType *ot)
2625 {
2626         /* identifiers */
2627         ot->name = "Set Scale";
2628         ot->description = "Set scale of scene by scaling camera (or it's parent if present)";
2629         ot->idname = "CLIP_OT_set_scale";
2630
2631         /* api callbacks */
2632         ot->exec = set_scale_exec;
2633         ot->invoke = set_scale_invoke;
2634         ot->poll = set_orientation_poll;
2635
2636         /* flags */
2637         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
2638
2639         /* properties */
2640         RNA_def_float(ot->srna, "distance", 0.0f, -FLT_MAX, FLT_MAX,
2641                 "Distance", "Distance between selected tracks", -100.0f, 100.0f);
2642 }
2643
2644 /********************** set solution scale operator *********************/
2645
2646 static int set_solution_scale_poll(bContext *C)
2647 {
2648         if (space_clip_size_poll(C)) {
2649                 SpaceClip *sc = CTX_wm_space_clip(C);
2650                 MovieClip *clip = ED_space_clip(sc);
2651                 MovieTracking *tracking = &clip->tracking;
2652                 MovieTrackingObject *tracking_object = BKE_tracking_active_object(tracking);
2653
2654                 return (tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0;
2655         }
2656
2657         return 0;
2658 }
2659
2660 static int set_solution_scale_exec(bContext *C, wmOperator *op)
2661 {
2662         return do_set_scale(C, op, 1);
2663 }
2664
2665 static int set_solution_scale_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
2666 {
2667         SpaceClip *sc = CTX_wm_space_clip(C);
2668         MovieClip *clip = ED_space_clip(sc);
2669
2670         if (!RNA_struct_property_is_set(op->ptr, "distance"))
2671                 RNA_float_set(op->ptr, "distance", clip->tracking.settings.object_distance);
2672
2673         return set_solution_scale_exec(C, op);
2674 }
2675
2676 void CLIP_OT_set_solution_scale(wmOperatorType *ot)
2677 {
2678         /* identifiers */
2679         ot->name = "Set Solution Scale";
2680         ot->description = "Set object solution scale using distance between two selected tracks";
2681         ot->idname = "CLIP_OT_set_solution_scale";
2682
2683         /* api callbacks */
2684         ot->exec = set_solution_scale_exec;
2685         ot->invoke = set_solution_scale_invoke;
2686         ot->poll = set_solution_scale_poll;
2687
2688         /* flags */
2689         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
2690
2691         /* properties */
2692         RNA_def_float(ot->srna, "distance", 0.0f, -FLT_MAX, FLT_MAX,
2693                 "Distance", "Distance between selected tracks", -100.0f, 100.0f);
2694 }
2695
2696 /********************** set principal center operator *********************/
2697
2698 static int set_center_principal_exec(bContext *C, wmOperator *UNUSED(op))
2699 {
2700         SpaceClip *sc = CTX_wm_space_clip(C);
2701         MovieClip *clip = ED_space_clip(sc);
2702         int width, height;
2703
2704         BKE_movieclip_get_size(clip, &sc->user, &width, &height);
2705
2706         if (width == 0 || height == 0)
2707                 return OPERATOR_CANCELLED;
2708
2709         clip->tracking.camera.principal[0] = ((float)width)/2.0f;
2710         clip->tracking.camera.principal[1] = ((float)height)/2.0f;
2711
2712         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, clip);
2713
2714         return OPERATOR_FINISHED;
2715 }
2716
2717 void CLIP_OT_set_center_principal(wmOperatorType *ot)
2718 {
2719         /* identifiers */
2720         ot->name = "Set Principal to Center";
2721         ot->description = "Set optical center to center of footage";
2722         ot->idname = "CLIP_OT_set_center_principal";
2723
2724         /* api callbacks */
2725         ot->exec = set_center_principal_exec;
2726         ot->poll = ED_space_clip_poll;
2727
2728         /* flags */
2729         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
2730 }
2731
2732 /********************** hide tracks operator *********************/
2733
2734 static int hide_tracks_exec(bContext *C, wmOperator *op)
2735 {
2736         SpaceClip *sc = CTX_wm_space_clip(C);
2737         MovieClip *clip = ED_space_clip(sc);
2738         MovieTrackingTrack *track;
2739         MovieTracking *tracking = &clip->tracking;
2740         ListBase *tracksbase = BKE_tracking_get_tracks(tracking);
2741         MovieTrackingTrack *act_track = BKE_tracking_active_track(tracking);
2742         int unselected;
2743
2744         unselected = RNA_boolean_get(op->ptr, "unselected");
2745
2746         track = tracksbase->first;
2747         while (track) {
2748                 if (unselected == 0 && TRACK_VIEW_SELECTED(sc, track)) {
2749                         track->flag |= TRACK_HIDDEN;
2750                 }
2751                 else if (unselected == 1 && !TRACK_VIEW_SELECTED(sc, track)) {
2752                         track->flag |= TRACK_HIDDEN;
2753                 }
2754
2755                 track = track->next;
2756         }
2757
2758         if (act_track && act_track->flag & TRACK_HIDDEN)
2759                 clip->tracking.act_track = NULL;
2760
2761         if (unselected == 0) {
2762                 /* no selection on screen now, unlock view so it can be scrolled nice again */
2763                 sc->flag &= ~SC_LOCK_SELECTION;
2764         }
2765
2766         WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, NULL);
2767
2768         return OPERATOR_FINISHED;
2769 }
2770
2771 void CLIP_OT_hide_tracks(wmOperatorType *ot)
2772 {
2773         /* identifiers */
2774         ot->name = "Hide Tracks";
2775         ot->description = "Hide selected tracks";
2776         ot->idname = "CLIP_OT_hide_tracks";
2777
2778         /* api callbacks */
2779         ot->exec = hide_tracks_exec;
2780         ot->poll = ED_space_clip_poll;
2781
2782         /* flags */
2783         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
2784
2785         /* properties */
2786         RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected tracks");
2787 }
2788
2789 /********************** hide tracks clear operator *********************/
2790
2791 static int hide_tracks_clear_exec(bContext *C, wmOperator *UNUSED(op))
2792 {
2793         SpaceClip *sc = CTX_wm_space_clip(C);
2794         MovieClip *clip = ED_space_clip(sc);
2795         ListBase *tracksbase = BKE_tracking_get_tracks(&clip->tracking);
2796         MovieTrackingTrack *track;
2797
2798         track = tracksbase->first;
2799         while (track) {
2800                 track->flag &= ~TRACK_HIDDEN;
2801
2802                 track = track->next;
2803         }
2804
2805         WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, NULL);
2806
2807         return OPERATOR_FINISHED;
2808 }
2809
2810 void CLIP_OT_hide_tracks_clear(wmOperatorType *ot)
2811 {
2812         /* identifiers */
2813         ot->name = "Hide Tracks Clear";
2814         ot->description = "Clear hide selected tracks";
2815         ot->idname = "CLIP_OT_hide_tracks_clear";
2816
2817         /* api callbacks */
2818         ot->exec = hide_tracks_clear_exec;
2819         ot->poll = ED_space_clip_poll;
2820
2821         /* flags */
2822         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
2823 }
2824
2825 /********************** detect features operator *********************/
2826
2827 static bGPDlayer *detect_get_layer(MovieClip *clip)
2828 {
2829         bGPDlayer *layer;
2830
2831         if (!clip->gpd)
2832                 return NULL;
2833
2834         layer = clip->gpd->layers.first;
2835         while (layer) {
2836                 if (layer->flag & GP_LAYER_ACTIVE)
2837                         return layer;
2838
2839                 layer = layer->next;
2840         }
2841
2842         return NULL;
2843 }
2844
2845 static int detect_features_exec(bContext *C, wmOperator *op)
2846 {
2847         SpaceClip *sc = CTX_wm_space_clip(C);
2848         MovieClip *clip = ED_space_clip(sc);
2849         int clip_flag = clip->flag & MCLIP_TIMECODE_FLAGS;
2850         ImBuf *ibuf = BKE_movieclip_get_ibuf_flag(clip, &sc->user, clip_flag, MOVIECLIP_CACHE_SKIP);
2851         MovieTracking *tracking = &clip->tracking;
2852         ListBase *tracksbase = BKE_tracking_get_tracks(tracking);
2853         MovieTrackingTrack *track = tracksbase->first;
2854         int placement = RNA_enum_get(op->ptr, "placement");
2855         int margin = RNA_int_get(op->ptr, "margin");
2856         int min_trackability = RNA_int_get(op->ptr, "min_trackability");
2857         int min_distance = RNA_int_get(op->ptr, "min_distance");
2858         int place_outside_layer = 0;
2859         bGPDlayer *layer = NULL;
2860
2861         if (placement != 0) {
2862                 layer = detect_get_layer(clip);
2863                 place_outside_layer = placement == 2;
2864         }
2865
2866         /* deselect existing tracks */
2867         while (track) {
2868                 track->flag &= ~SELECT;
2869                 track->pat_flag &= ~SELECT;
2870                 track->search_flag &= ~SELECT;
2871
2872                 track = track->next;
2873         }
2874
2875         BKE_tracking_detect_fast(tracking, tracksbase, ibuf, sc->user.framenr, margin,
2876                                 min_trackability, min_distance, layer, place_outside_layer);
2877
2878         IMB_freeImBuf(ibuf);
2879
2880         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, NULL);
2881
2882         return OPERATOR_FINISHED;
2883 }
2884
2885 void CLIP_OT_detect_features(wmOperatorType *ot)
2886 {
2887         static EnumPropertyItem placement_items[] = {
2888                         {0, "FRAME",                    0, "Whole Frame",                       "Place markers across the whole frame"},
2889                         {1, "INSIDE_GPENCIL",   0, "Inside grease pencil",      "Place markers only inside areas outlined with grease pencil"},
2890                         {2, "OUTSIDE_GPENCIL",  0, "Outside grease pencil",     "Place markers only outside areas outlined with grease pencil"},
2891                         {0, NULL, 0, NULL, NULL}
2892         };
2893
2894         /* identifiers */
2895         ot->name = "Detect Features";
2896         ot->description = "Automatically detect features and place markers to track";
2897         ot->idname = "CLIP_OT_detect_features";
2898
2899         /* api callbacks */
2900         ot->exec = detect_features_exec;
2901         ot->poll = space_clip_frame_poll;
2902
2903         /* flags */
2904         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
2905
2906         /* properties */
2907         RNA_def_enum(ot->srna, "placement", placement_items, 0, "Placement", "Placement for detected features");
2908         RNA_def_int(ot->srna, "margin", 16, 0, INT_MAX, "Margin", "Only corners further than margin pixels from the image edges are considered", 0, 300);
2909         RNA_def_int(ot->srna, "min_trackability", 16, 0, INT_MAX, "Trackability", "Minimum trackability score to add a corner", 0, 300);
2910         RNA_def_int(ot->srna, "min_distance", 120, 0, INT_MAX, "Distance", "Minimal distance accepted between two corners", 0, 300);
2911 }
2912
2913 /********************** frame jump operator *********************/
2914
2915 static int frame_jump_exec(bContext *C, wmOperator *op)
2916 {
2917         Scene *scene = CTX_data_scene(C);
2918         SpaceClip *sc = CTX_wm_space_clip(C);
2919         MovieClip *clip = ED_space_clip(sc);
2920         MovieTrackingTrack *track;
2921         int pos = RNA_enum_get(op->ptr, "position");
2922         int delta;
2923
2924         if (pos <= 1) { /* jump to path */
2925                 track = BKE_tracking_active_track(&clip->tracking);
2926
2927                 if (!track)
2928                         return OPERATOR_CANCELLED;
2929
2930                 delta = pos == 1 ? 1 : -1;
2931
2932                 while (sc->user.framenr+delta >= SFRA && sc->user.framenr+delta <= EFRA) {
2933                         MovieTrackingMarker *marker = BKE_tracking_exact_marker(track, sc->user.framenr+delta);
2934
2935                         if (!marker || marker->flag & MARKER_DISABLED)
2936                                 break;
2937
2938                         sc->user.framenr += delta;
2939                 }
2940         }
2941         else {  /* to to failed frame */
2942                 if (clip->tracking.reconstruction.flag & TRACKING_RECONSTRUCTED) {
2943                         int a = sc->user.framenr;
2944                         MovieTracking *tracking = &clip->tracking;
2945                         MovieTrackingObject *object = BKE_tracking_active_object(tracking);
2946
2947                         delta = pos == 3 ? 1 : -1;
2948
2949                         a += delta;
2950
2951                         while (a+delta >= SFRA && a+delta <= EFRA) {
2952                                 MovieReconstructedCamera *cam;
2953
2954                                 cam = BKE_tracking_get_reconstructed_camera(tracking, object, a);
2955
2956                                 if (!cam) {
2957                                         sc->user.framenr = a;
2958
2959                                         break;
2960                                 }
2961
2962                                 a += delta;
2963                         }
2964                 }
2965         }
2966
2967         if (CFRA != sc->user.framenr) {
2968                 CFRA = sc->user.framenr;
2969                 sound_seek_scene(CTX_data_main(C), CTX_data_scene(C));
2970
2971                 WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
2972         }
2973
2974         WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, NULL);
2975
2976         return OPERATOR_FINISHED;
2977 }
2978
2979 void CLIP_OT_frame_jump(wmOperatorType *ot)
2980 {
2981         static EnumPropertyItem position_items[] = {
2982                         {0, "PATHSTART",        0, "Path Start",                "Jump to start of current path"},
2983                         {1, "PATHEND",          0, "Path End",                  "Jump to end of current path"},
2984                         {2, "FAILEDPREV",       0, "Previous Failed",   "Jump to previous failed frame"},
2985                         {2, "FAILNEXT",         0, "Next Failed",               "Jump to next failed frame"},
2986                         {0, NULL, 0, NULL, NULL}
2987         };
2988
2989         /* identifiers */
2990         ot->name = "Jump to Frame";
2991         ot->description = "Jump to special frame";
2992         ot->idname = "CLIP_OT_frame_jump";
2993
2994         /* api callbacks */
2995         ot->exec = frame_jump_exec;
2996         ot->poll = ED_space_clip_poll;
2997
2998         /* flags */
2999         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
3000
3001         /* properties */
3002         RNA_def_enum(ot->srna, "position", position_items, 0, "Position", "Position to jump to");
3003 }
3004
3005 /********************** join tracks operator *********************/
3006
3007 static int join_tracks_exec(bContext *C, wmOperator *op)
3008 {
3009         SpaceClip *sc = CTX_wm_space_clip(C);
3010         MovieClip *clip = ED_space_clip(sc);
3011         MovieTracking *tracking = &clip->tracking;
3012         ListBase *tracksbase = BKE_tracking_get_tracks(tracking);
3013         MovieTrackingTrack *act_track, *track, *next;
3014
3015         act_track = BKE_tracking_active_track(tracking);
3016
3017         if (!act_track) {
3018                 BKE_report(op->reports, RPT_ERROR, "No active track to join to");
3019                 return OPERATOR_CANCELLED;
3020         }
3021
3022         track = tracksbase->first;
3023         while (track) {
3024                 next = track->next;
3025
3026                 if (TRACK_VIEW_SELECTED(sc, track) && track != act_track) {
3027                         BKE_tracking_join_tracks(act_track, track);
3028
3029                         if (tracking->stabilization.rot_track == track)
3030                                 tracking->stabilization.rot_track = act_track;
3031
3032                         BKE_tracking_free_track(track);
3033                         BLI_freelinkN(tracksbase, track);
3034                 }
3035
3036                 track = next;
3037         }
3038
3039         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, clip);
3040
3041         return OPERATOR_FINISHED;
3042 }
3043
3044 void CLIP_OT_join_tracks(wmOperatorType *ot)
3045 {
3046         /* identifiers */
3047         ot->name = "Join Tracks";
3048         ot->description = "Join selected tracks";
3049         ot->idname = "CLIP_OT_join_tracks";
3050
3051         /* api callbacks */
3052         ot->exec = join_tracks_exec;
3053         ot->poll = space_clip_size_poll;
3054
3055         /* flags */
3056         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
3057 }
3058
3059 /********************** lock tracks operator *********************/
3060
3061 static int lock_tracks_exec(bContext *C, wmOperator *op)
3062 {
3063         SpaceClip *sc = CTX_wm_space_clip(C);
3064         MovieClip *clip = ED_space_clip(sc);
3065         MovieTracking *tracking = &clip->tracking;
3066         ListBase *tracksbase = BKE_tracking_get_tracks(tracking);
3067         MovieTrackingTrack *track = tracksbase->first;
3068         int action = RNA_enum_get(op->ptr, "action");
3069
3070         while (track) {
3071                 if (TRACK_VIEW_SELECTED(sc, track)) {
3072                         if (action == 0)
3073                                 track->flag |= TRACK_LOCKED;
3074                         else if (action == 1)
3075                                 track->flag &= ~TRACK_LOCKED;
3076                         else track->flag ^= TRACK_LOCKED;
3077                 }
3078
3079                 track = track->next;
3080         }
3081
3082         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
3083
3084         return OPERATOR_FINISHED;
3085 }
3086
3087 void CLIP_OT_lock_tracks(wmOperatorType *ot)
3088 {
3089         static EnumPropertyItem actions_items[] = {
3090                         {0, "LOCK", 0, "Lock", "Lock selected tracks"},
3091                         {1, "UNLOCK", 0, "Unlock", "Unlock selected tracks"},
3092                         {2, "TOGGLE", 0, "Toggle", "Toggle locked flag for selected tracks"},
3093                         {0, NULL, 0, NULL, NULL}
3094         };
3095
3096         /* identifiers */
3097         ot->name = "Lock Tracks";
3098         ot->description = "Lock/unlock selected tracks";
3099         ot->idname = "CLIP_OT_lock_tracks";
3100
3101         /* api callbacks */
3102         ot->exec = lock_tracks_exec;
3103         ot->poll = ED_space_clip_poll;
3104
3105         /* flags */
3106         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
3107
3108         /* properties */
3109         RNA_def_enum(ot->srna, "action", actions_items, 0, "Action", "Lock action to execute");
3110 }
3111
3112 /********************** track copy color operator *********************/
3113
3114 static int track_copy_color_exec(bContext *C, wmOperator *UNUSED(op))
3115 {
3116         SpaceClip *sc = CTX_wm_space_clip(C);
3117         MovieClip *clip = ED_space_clip(sc);
3118         MovieTracking *tracking = &clip->tracking;
3119         ListBase *tracksbase = BKE_tracking_get_tracks(tracking);
3120         MovieTrackingTrack *track, *act_track = BKE_tracking_active_track(tracking);
3121
3122         if (!act_track)
3123                 return OPERATOR_CANCELLED;
3124
3125         track = tracksbase->first;
3126         while (track) {
3127                 if (TRACK_VIEW_SELECTED(sc, track) && track != act_track) {
3128                         track->flag &= ~TRACK_CUSTOMCOLOR;
3129
3130                         if (act_track->flag & TRACK_CUSTOMCOLOR) {
3131                                 copy_v3_v3(track->color, act_track->color);
3132                                 track->flag |= TRACK_CUSTOMCOLOR;
3133                         }
3134                 }
3135
3136                 track = track->next;
3137         }
3138
3139         WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, clip);
3140
3141         return OPERATOR_FINISHED;
3142 }
3143
3144 void CLIP_OT_track_copy_color(wmOperatorType *ot)
3145 {
3146         /* identifiers */
3147         ot->name = "Copy Color";
3148         ot->description = "Copy color to all selected tracks";
3149         ot->idname = "CLIP_OT_track_copy_color";
3150
3151         /* api callbacks */
3152         ot->exec = track_copy_color_exec;
3153         ot->poll = ED_space_clip_poll;
3154
3155         /* flags */
3156         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
3157 }
3158
3159 /********************** add 2d stabilization tracks operator *********************/
3160
3161 static int stabilize_2d_add_exec(bContext *C, wmOperator *UNUSED(op))
3162 {
3163         SpaceClip *sc = CTX_wm_space_clip(C);
3164         MovieClip *clip = ED_space_clip(sc);
3165         MovieTracking *tracking = &clip->tracking;
3166         ListBase *tracksbase = BKE_tracking_get_tracks(tracking);
3167         MovieTrackingTrack *track;
3168         MovieTrackingStabilization *stab = &tracking->stabilization;
3169         int update = 0;
3170
3171         track = tracksbase->first;
3172         while (track) {
3173                 if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_USE_2D_STAB)==0) {
3174                         track->flag |= TRACK_USE_2D_STAB;
3175                         stab->tot_track++;
3176
3177                         update = 1;
3178                 }
3179
3180                 track = track->next;
3181         }
3182
3183         if (update) {
3184                 stab->ok = 0;
3185
3186                 DAG_id_tag_update(&clip->id, 0);
3187                 WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, clip);
3188         }
3189
3190         return OPERATOR_FINISHED;
3191 }
3192
3193 void CLIP_OT_stabilize_2d_add(wmOperatorType *ot)
3194 {
3195         /* identifiers */
3196         ot->name = "Add Stabilization Tracks";
3197         ot->description = "Add selected tracks to 2D stabilization tool";
3198         ot->idname = "CLIP_OT_stabilize_2d_add";
3199
3200         /* api callbacks */
3201         ot->exec = stabilize_2d_add_exec;
3202         ot->poll = ED_space_clip_poll;
3203
3204         /* flags */
3205         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
3206 }
3207
3208 /********************** remove 2d stabilization tracks operator *********************/
3209
3210 static int stabilize_2d_remove_exec(bContext *C, wmOperator *UNUSED(op))
3211 {
3212         SpaceClip *sc = CTX_wm_space_clip(C);
3213         MovieClip *clip = ED_space_clip(sc);
3214         MovieTracking *tracking = &clip->tracking;
3215         MovieTrackingStabilization *stab = &tracking->stabilization;
3216         ListBase *tracksbase = BKE_tracking_get_tracks(tracking);
3217         MovieTrackingTrack *track;
3218         int a = 0, update = 0;
3219
3220         track = tracksbase->first;
3221         while (track) {
3222                 if (track->flag & TRACK_USE_2D_STAB) {
3223                         if (a == stab->act_track) {
3224                                 track->flag &= ~TRACK_USE_2D_STAB;
3225
3226                                 stab->act_track--;
3227                                 stab->tot_track--;
3228
3229                                 if (stab->act_track<0)
3230                                         stab->act_track = 0;
3231
3232                                 update = 1;
3233
3234                                 break;
3235                         }
3236
3237                         a++;
3238                 }
3239
3240                 track = track->next;
3241         }
3242
3243         if (update) {
3244                 stab->ok = 0;
3245
3246                 DAG_id_tag_update(&clip->id, 0);
3247                 WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, clip);
3248         }
3249
3250         return OPERATOR_FINISHED;
3251 }
3252
3253 void CLIP_OT_stabilize_2d_remove(wmOperatorType *ot)
3254 {
3255         /* identifiers */
3256         ot->name = "Remove Stabilization Track";
3257         ot->description = "Remove selected track from stabilization";
3258         ot->idname = "CLIP_OT_stabilize_2d_remove";
3259
3260         /* api callbacks */
3261         ot->exec = stabilize_2d_remove_exec;
3262         ot->poll = ED_space_clip_poll;
3263
3264         /* flags */
3265         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
3266 }
3267
3268 /********************** select 2d stabilization tracks operator *********************/
3269
3270 static int stabilize_2d_select_exec(bContext *C, wmOperator *UNUSED(op))
3271 {
3272         SpaceClip *sc = CTX_wm_space_clip(C);
3273         MovieClip *clip = ED_space_clip(sc);
3274         MovieTracking *tracking = &clip->tracking;
3275         ListBase *tracksbase = BKE_tracking_get_tracks(tracking);
3276         MovieTrackingTrack *track;
3277         int update = 0;
3278
3279         track = tracksbase->first;
3280         while (track) {
3281                 if (track->flag & TRACK_USE_2D_STAB) {
3282                         BKE_tracking_track_flag(track, TRACK_AREA_ALL, SELECT, 0);
3283
3284                         update = 1;
3285                 }
3286
3287                 track = track->next;
3288         }
3289
3290         if (update)
3291                 WM_event_add_notifier(C, NC_MOVIECLIP|ND_SELECT, clip);
3292
3293         return OPERATOR_FINISHED;
3294 }
3295
3296 void CLIP_OT_stabilize_2d_select(wmOperatorType *ot)
3297 {
3298         /* identifiers */
3299         ot->name = "Select Stabilization Tracks";
3300         ot->description = "Select track which are used for stabilization";
3301         ot->idname = "CLIP_OT_stabilize_2d_select";
3302
3303         /* api callbacks */
3304         ot->exec = stabilize_2d_select_exec;
3305         ot->poll = ED_space_clip_poll;
3306
3307         /* flags */
3308         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
3309 }
3310
3311 /********************** set 2d stabilization rotation track operator *********************/
3312
3313 static int stabilize_2d_set_rotation_exec(bContext *C, wmOperator *UNUSED(op))
3314 {
3315         SpaceClip *sc = CTX_wm_space_clip(C);
3316         MovieClip *clip = ED_space_clip(sc);
3317         MovieTracking *tracking = &clip->tracking;
3318         MovieTrackingTrack *act_track = BKE_tracking_active_track(tracking);
3319