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