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