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