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