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