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