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