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