svn merge ^/trunk/blender -r43830:43864
[blender-staging.git] / source / blender / editors / space_clip / tracking_ops.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2011 Blender Foundation.
19  * All rights reserved.
20  *
21  *
22  * Contributor(s): Blender Foundation,
23  *                 Sergey Sharybin
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/space_clip/tracking_ops.c
29  *  \ingroup spclip
30  */
31
32 #include "MEM_guardedalloc.h"
33
34 #include "DNA_camera_types.h"
35 #include "DNA_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         MovieTrackingMarker *marker;
1018         ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
1019         int action= RNA_enum_get(op->ptr, "action");
1020         int framenr= sc->user.framenr;
1021         int has_selection= 0;
1022
1023         if(action == SEL_TOGGLE){
1024                 action= SEL_SELECT;
1025                 track= tracksbase->first;
1026                 while(track) {
1027                         if(TRACK_VIEW_SELECTED(sc, track)) {
1028                                 marker= BKE_tracking_get_marker(track, framenr);
1029
1030                                 if(MARKER_VISIBLE(sc, marker)) {
1031                                         action= SEL_DESELECT;
1032                                         break;
1033                                 }
1034                         }
1035
1036                         track= track->next;
1037                 }
1038         }
1039
1040         track= tracksbase->first;
1041         while(track) {
1042                 if((track->flag&TRACK_HIDDEN)==0) {
1043                         marker= BKE_tracking_get_marker(track, framenr);
1044
1045                         if(MARKER_VISIBLE(sc, marker)) {
1046                                 switch (action) {
1047                                         case SEL_SELECT:
1048                                                 track->flag|= SELECT;
1049                                                 track->pat_flag|= SELECT;
1050                                                 track->search_flag|= SELECT;
1051                                                 break;
1052                                         case SEL_DESELECT:
1053                                                 track->flag&= ~SELECT;
1054                                                 track->pat_flag&= ~SELECT;
1055                                                 track->search_flag&= ~SELECT;
1056                                                 break;
1057                                         case SEL_INVERT:
1058                                                 track->flag^= SELECT;
1059                                                 track->pat_flag^= SELECT;
1060                                                 track->search_flag^= SELECT;
1061                                                 break;
1062                                 }
1063                         }
1064                 }
1065
1066                 if(TRACK_VIEW_SELECTED(sc, track))
1067                         has_selection= 1;
1068
1069                 track= track->next;
1070         }
1071
1072         if(!has_selection)
1073                 sc->flag&= ~SC_LOCK_SELECTION;
1074
1075         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, NULL);
1076
1077         return OPERATOR_FINISHED;
1078 }
1079
1080 void CLIP_OT_select_all(wmOperatorType *ot)
1081 {
1082         /* identifiers */
1083         ot->name= "Select or Deselect All";
1084         ot->description= "Change selection of all tracking markers";
1085         ot->idname= "CLIP_OT_select_all";
1086
1087         /* api callbacks */
1088         ot->exec= select_all_exec;
1089         ot->poll= ED_space_clip_poll;
1090
1091         /* flags */
1092         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1093
1094         WM_operator_properties_select_all(ot);
1095 }
1096
1097 /********************** select grouped operator *********************/
1098
1099 static int select_groped_exec(bContext *C, wmOperator *op)
1100 {
1101         SpaceClip *sc= CTX_wm_space_clip(C);
1102         MovieClip *clip= ED_space_clip(sc);
1103         MovieTrackingTrack *track;
1104         MovieTrackingMarker *marker;
1105         MovieTracking *tracking= &clip->tracking;
1106         ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
1107         int group= RNA_enum_get(op->ptr, "group");
1108
1109         track= tracksbase->first;
1110         while(track) {
1111                 int ok= 0;
1112
1113                 marker= BKE_tracking_get_marker(track, sc->user.framenr);
1114
1115                 if(group==0) { /* Keyframed */
1116                         ok= marker->framenr==sc->user.framenr && (marker->flag&MARKER_TRACKED)==0;
1117                 }
1118                 else if(group==1) { /* Estimated */
1119                         ok= marker->framenr!=sc->user.framenr;
1120                 }
1121                 else if(group==2) { /* tracked */
1122                         ok= marker->framenr==sc->user.framenr && (marker->flag&MARKER_TRACKED);
1123                 }
1124                 else if(group==3) { /* locked */
1125                         ok= track->flag&TRACK_LOCKED;
1126                 }
1127                 else if(group==4) { /* disabled */
1128                         ok= marker->flag&MARKER_DISABLED;
1129                 }
1130                 else if(group==5) { /* color */
1131                         MovieTrackingTrack *act_track= BKE_tracking_active_track(tracking);
1132
1133                         if(act_track) {
1134                                 ok= (track->flag&TRACK_CUSTOMCOLOR) == (act_track->flag&TRACK_CUSTOMCOLOR);
1135
1136                                 if(ok && track->flag&TRACK_CUSTOMCOLOR)
1137                                         ok= equals_v3v3(track->color, act_track->color);
1138                         }
1139                 }
1140                 else if(group==6) { /* failed */
1141                         ok= (track->flag&TRACK_HAS_BUNDLE) == 0;
1142                 }
1143
1144                 if(ok) {
1145                         track->flag|= SELECT;
1146                         if(sc->flag&SC_SHOW_MARKER_PATTERN) track->pat_flag|= SELECT;;
1147                         if(sc->flag&SC_SHOW_MARKER_SEARCH) track->search_flag|= SELECT;;
1148                 }
1149
1150                 track= track->next;
1151         }
1152
1153         WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, clip);
1154
1155         return OPERATOR_FINISHED;
1156 }
1157
1158 void CLIP_OT_select_grouped(wmOperatorType *ot)
1159 {
1160         static EnumPropertyItem select_group_items[] = {
1161                         {0, "KEYFRAMED", 0, "Keyframed tracks", "Select all keyframed tracks"},
1162                         {1, "ESTIMATED", 0, "Estimated tracks", "Select all estimated tracks"},
1163                         {2, "TRACKED", 0, "Tracked tracks", "Select all tracked tracks"},
1164                         {3, "LOCKED", 0, "Locked tracks", "Select all locked tracks"},
1165                         {4, "DISABLED", 0, "Disabled tracks", "Select all disabled tracks"},
1166                         {5, "COLOR", 0, "Tracks with same color", "Select all tracks with same color as active track"},
1167                         {6, "FAILED", 0, "Failed Tracks", "Select all tracks which failed to be reconstructed"},
1168                         {0, NULL, 0, NULL, NULL}
1169         };
1170
1171         /* identifiers */
1172         ot->name= "Select Grouped";
1173         ot->description= "Joint Selected Tracks";
1174         ot->idname= "CLIP_OT_select_grouped";
1175
1176         /* api callbacks */
1177         ot->exec= select_groped_exec;
1178         ot->poll= space_clip_frame_poll;
1179
1180         /* flags */
1181         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1182
1183         /* proeprties */
1184         RNA_def_enum(ot->srna, "group", select_group_items, TRACK_CLEAR_REMAINED, "Action", "Clear action to execute");
1185 }
1186
1187 /********************** track operator *********************/
1188
1189 typedef struct TrackMarkersJob {
1190         struct MovieTrackingContext *context;   /* tracking context */
1191         int sfra, efra, lastfra;        /* Start, end and recently tracked frames */
1192         int backwards;                          /* Backwards tracking flag */
1193         MovieClip *clip;                        /* Clip which is tracking */
1194         float delay;                            /* Delay in milliseconds to allow tracking at fixed FPS */
1195
1196         struct Main *main;
1197         struct Scene *scene;
1198         struct bScreen *screen;
1199 } TrackMarkersJob;
1200
1201 static int track_markers_testbreak(void)
1202 {
1203         return G.afbreek;
1204 }
1205
1206 static int track_count_markers(SpaceClip *sc, MovieClip *clip)
1207 {
1208         int tot= 0;
1209         ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
1210         MovieTrackingTrack *track;
1211         int framenr= sc->user.framenr;
1212
1213         track= tracksbase->first;
1214         while(track) {
1215                 if(TRACK_VIEW_SELECTED(sc, track) && (track->flag&TRACK_LOCKED)==0) {
1216                         MovieTrackingMarker *marker= BKE_tracking_get_marker(track, framenr);
1217
1218                         if (!marker || (marker->flag&MARKER_DISABLED) == 0)
1219                                 tot++;
1220                 }
1221
1222                 track= track->next;
1223         }
1224
1225         return tot;
1226 }
1227
1228 static void clear_invisible_track_selection(SpaceClip *sc, MovieClip *clip)
1229 {
1230         ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
1231         int hidden = 0;
1232
1233         if ((sc->flag&SC_SHOW_MARKER_PATTERN)==0)
1234                 hidden |= TRACK_AREA_PAT;
1235
1236         if ((sc->flag&SC_SHOW_MARKER_SEARCH)==0)
1237                 hidden |= TRACK_AREA_SEARCH;
1238
1239         if (hidden) {
1240                 MovieTrackingTrack *track = tracksbase->first;
1241
1242                 while(track) {
1243                         BKE_tracking_track_flag(track, hidden, SELECT, 1);
1244
1245                         track = track->next;
1246                 }
1247         }
1248 }
1249
1250 static void track_init_markers(SpaceClip *sc, MovieClip *clip, int *frames_limit_r)
1251 {
1252         ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
1253         MovieTrackingTrack *track;
1254         int framenr= sc->user.framenr;
1255         int frames_limit= 0;
1256
1257         clear_invisible_track_selection(sc, clip);
1258
1259         track= tracksbase->first;
1260         while(track) {
1261                 if(TRACK_SELECTED(track)) {
1262                         if((track->flag&TRACK_HIDDEN)==0 && (track->flag&TRACK_LOCKED)==0) {
1263                                 BKE_tracking_ensure_marker(track, framenr);
1264
1265                                 if(track->frames_limit) {
1266                                         if(frames_limit==0)
1267                                                 frames_limit= track->frames_limit;
1268                                         else
1269                                                 frames_limit= MIN2(frames_limit, track->frames_limit);
1270                                 }
1271                         }
1272                 }
1273
1274                 track= track->next;
1275         }
1276
1277         *frames_limit_r= frames_limit;
1278 }
1279
1280 static int track_markers_check_direction(int backwards, int curfra, int efra)
1281 {
1282         if(backwards) {
1283                 if(curfra<efra) return 0;
1284         }
1285         else {
1286                 if(curfra>efra) return 0;
1287         }
1288
1289         return 1;
1290 }
1291
1292 static int track_markers_initjob(bContext *C, TrackMarkersJob *tmj, int backwards)
1293 {
1294         SpaceClip *sc= CTX_wm_space_clip(C);
1295         MovieClip *clip= ED_space_clip(sc);
1296         Scene *scene= CTX_data_scene(C);
1297         MovieTrackingSettings *settings= &clip->tracking.settings;
1298         int frames_limit;
1299
1300         track_init_markers(sc, clip, &frames_limit);
1301
1302         tmj->sfra= sc->user.framenr;
1303         tmj->clip= clip;
1304         tmj->backwards= backwards;
1305
1306         if(backwards) tmj->efra= SFRA;
1307         else tmj->efra= EFRA;
1308
1309         /* limit frames to be tracked by user setting */
1310         if(frames_limit) {
1311                 if(backwards) tmj->efra= MAX2(tmj->efra, tmj->sfra-frames_limit);
1312                 else tmj->efra= MIN2(tmj->efra, tmj->sfra+frames_limit);
1313         }
1314
1315         if(settings->speed!=TRACKING_SPEED_FASTEST) {
1316                 tmj->delay= 1.0f/scene->r.frs_sec*1000.0f;
1317
1318                 if(settings->speed==TRACKING_SPEED_HALF) tmj->delay*= 2;
1319                 else if(settings->speed==TRACKING_SPEED_QUARTER) tmj->delay*= 4;
1320                 else if(settings->speed==TRACKING_SPEED_DOUBLE) tmj->delay/= 2;
1321         }
1322
1323         tmj->context= BKE_tracking_context_new(clip, &sc->user, backwards, 1);
1324
1325         clip->tracking_context= tmj->context;
1326
1327         tmj->lastfra= tmj->sfra;
1328
1329         /* XXX: silly to store this, but this data is needed to update scene and movieclip
1330                 frame numbers when tracking is finished. This introduces better feedback for artists.
1331                 Maybe there's another way to solve this problem, but can't think better way atm.
1332                 Anyway, this way isn't more unstable as animation rendering animation
1333                 which uses the same approach (except storing screen). */
1334         tmj->scene= scene;
1335         tmj->main= CTX_data_main(C);
1336         tmj->screen= CTX_wm_screen(C);
1337
1338         return track_markers_check_direction(backwards, tmj->sfra, tmj->efra);
1339 }
1340
1341 static void track_markers_startjob(void *tmv, short *stop, short *do_update, float *progress)
1342 {
1343         TrackMarkersJob *tmj= (TrackMarkersJob *)tmv;
1344         int framenr= tmj->sfra;
1345         //double t= PIL_check_seconds_timer();
1346
1347         while(framenr != tmj->efra) {
1348                 if(tmj->delay>0) {
1349                         /* tracking should happen with fixed fps. Calculate time
1350                            using current timer value before tracking frame and after.
1351
1352                            Small (and maybe unneeded optimization): do not calculate exec_time
1353                            for "Fastest" tracking */
1354
1355                         double start_time= PIL_check_seconds_timer(), exec_time;
1356
1357                         if(!BKE_tracking_next(tmj->context))
1358                                 break;
1359
1360                         exec_time= PIL_check_seconds_timer()-start_time;
1361                         if(tmj->delay > (float)exec_time)
1362                                 PIL_sleep_ms(tmj->delay-(float)exec_time);
1363                 } else if(!BKE_tracking_next(tmj->context))
1364                                 break;
1365
1366                 *do_update= 1;
1367                 *progress=(float)(framenr-tmj->sfra) / (tmj->efra-tmj->sfra);
1368
1369                 if(tmj->backwards) framenr--;
1370                 else framenr++;
1371
1372                 tmj->lastfra= framenr;
1373
1374                 if(*stop || track_markers_testbreak())
1375                         break;
1376         }
1377
1378         //printf("Tracking time: %lf\n", PIL_check_seconds_timer()-t);
1379 }
1380
1381 static void track_markers_updatejob(void *tmv)
1382 {
1383         TrackMarkersJob *tmj= (TrackMarkersJob *)tmv;
1384
1385         BKE_tracking_sync(tmj->context);
1386 }
1387
1388 static void track_markers_freejob(void *tmv)
1389 {
1390         TrackMarkersJob *tmj= (TrackMarkersJob *)tmv;
1391
1392         tmj->clip->tracking_context= NULL;
1393         tmj->scene->r.cfra= tmj->lastfra;
1394         ED_update_for_newframe(tmj->main, tmj->scene, tmj->screen, 0);
1395
1396         BKE_tracking_sync(tmj->context);
1397         BKE_tracking_context_free(tmj->context);
1398
1399         MEM_freeN(tmj);
1400
1401         WM_main_add_notifier(NC_SCENE|ND_FRAME, tmj->scene);
1402 }
1403
1404 static int track_markers_exec(bContext *C, wmOperator *op)
1405 {
1406         SpaceClip *sc= CTX_wm_space_clip(C);
1407         MovieClip *clip= ED_space_clip(sc);
1408         Scene *scene= CTX_data_scene(C);
1409         struct MovieTrackingContext *context;
1410         int framenr= sc->user.framenr;
1411         int sfra= framenr, efra;
1412         int backwards= RNA_boolean_get(op->ptr, "backwards");
1413         int sequence= RNA_boolean_get(op->ptr, "sequence");
1414         int frames_limit;
1415
1416         if(track_count_markers(sc, clip)==0)
1417                 return OPERATOR_CANCELLED;
1418
1419         track_init_markers(sc, clip, &frames_limit);
1420
1421         if(backwards) efra= SFRA;
1422         else efra= EFRA;
1423
1424         /* limit frames to be tracked by user setting */
1425         if(frames_limit) {
1426                 if(backwards) efra= MAX2(efra, sfra-frames_limit);
1427                 else efra= MIN2(efra, sfra+frames_limit);
1428         }
1429
1430         if(!track_markers_check_direction(backwards, framenr, efra))
1431                 return OPERATOR_CANCELLED;
1432
1433         /* do not disable tracks due to threshold when tracking frame-by-frame */
1434         context= BKE_tracking_context_new(clip, &sc->user, backwards, sequence);
1435
1436         while(framenr != efra) {
1437                 if(!BKE_tracking_next(context))
1438                         break;
1439
1440                 if(backwards) framenr--;
1441                 else framenr++;
1442
1443                 if(!sequence)
1444                         break;
1445         }
1446
1447         BKE_tracking_sync(context);
1448         BKE_tracking_context_free(context);
1449
1450         /* update scene current frame to the lastes tracked frame */
1451         scene->r.cfra= framenr;
1452
1453         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
1454         WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
1455
1456         return OPERATOR_FINISHED;
1457 }
1458
1459 static int track_markers_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
1460 {
1461         TrackMarkersJob *tmj;
1462         ScrArea *sa= CTX_wm_area(C);
1463         SpaceClip *sc= CTX_wm_space_clip(C);
1464         MovieClip *clip= ED_space_clip(sc);
1465         wmJob *steve;
1466         int backwards= RNA_boolean_get(op->ptr, "backwards");
1467         int sequence= RNA_boolean_get(op->ptr, "sequence");
1468
1469         if(WM_jobs_test(CTX_wm_manager(C), CTX_wm_area(C))) {
1470                 /* only one tracking is allowed at a time */
1471                 return OPERATOR_CANCELLED;
1472         }
1473
1474         if(clip->tracking_context)
1475                 return OPERATOR_CANCELLED;
1476
1477         if(track_count_markers(sc, clip)==0)
1478                 return OPERATOR_CANCELLED;
1479
1480         if(!sequence)
1481                 return track_markers_exec(C, op);
1482
1483         tmj= MEM_callocN(sizeof(TrackMarkersJob), "TrackMarkersJob data");
1484         if(!track_markers_initjob(C, tmj, backwards)) {
1485                 track_markers_freejob(tmj);
1486
1487                 return OPERATOR_CANCELLED;
1488         }
1489
1490         /* setup job */
1491         steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), sa, "Track Markers", WM_JOB_PROGRESS);
1492         WM_jobs_customdata(steve, tmj, track_markers_freejob);
1493
1494         /* if there's delay set in tracking job, tracking should happen
1495            with fixed FPS. To deal with editor refresh we have to syncronize
1496            tracks from job and tracks in clip. Do this in timer callback
1497            to prevent threading conflicts. */
1498         if(tmj->delay>0) WM_jobs_timer(steve, tmj->delay/1000.0f, NC_MOVIECLIP|NA_EVALUATED, 0);
1499         else WM_jobs_timer(steve, 0.2, NC_MOVIECLIP|NA_EVALUATED, 0);
1500
1501         WM_jobs_callbacks(steve, track_markers_startjob, NULL, track_markers_updatejob, NULL);
1502
1503         G.afbreek= 0;
1504
1505         WM_jobs_start(CTX_wm_manager(C), steve);
1506         WM_cursor_wait(0);
1507
1508         /* add modal handler for ESC */
1509         WM_event_add_modal_handler(C, op);
1510
1511         return OPERATOR_RUNNING_MODAL;
1512 }
1513
1514 static int track_markers_modal(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
1515 {
1516         /* no running tracking, remove handler and pass through */
1517         if(0==WM_jobs_test(CTX_wm_manager(C), CTX_wm_area(C)))
1518                 return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
1519
1520         /* running tracking */
1521         switch (event->type) {
1522                 case ESCKEY:
1523                         return OPERATOR_RUNNING_MODAL;
1524                         break;
1525         }
1526
1527         return OPERATOR_PASS_THROUGH;
1528 }
1529
1530 void CLIP_OT_track_markers(wmOperatorType *ot)
1531 {
1532         /* identifiers */
1533         ot->name= "Track Markers";
1534         ot->description= "Track selected markers";
1535         ot->idname= "CLIP_OT_track_markers";
1536
1537         /* api callbacks */
1538         ot->exec= track_markers_exec;
1539         ot->invoke= track_markers_invoke;
1540         ot->poll= space_clip_frame_poll;
1541         ot->modal= track_markers_modal;
1542
1543         /* flags */
1544         ot->flag= OPTYPE_UNDO;
1545
1546         /* properties */
1547         RNA_def_boolean(ot->srna, "backwards", 0, "Backwards", "Do backwards tracking");
1548         RNA_def_boolean(ot->srna, "sequence", 0, "Track Sequence", "Track marker during image sequence rather than single image");
1549 }
1550
1551 /********************** solve camera operator *********************/
1552
1553 typedef struct {
1554         Scene *scene;
1555         MovieClip *clip;
1556         MovieClipUser user;
1557
1558         ReportList *reports;
1559
1560         char stats_message[256];
1561
1562         struct MovieReconstructContext *context;
1563 } SolveCameraJob;
1564
1565 static int solve_camera_initjob(bContext *C, SolveCameraJob *scj, wmOperator *op, char *error_msg, int max_error)
1566 {
1567         SpaceClip *sc= CTX_wm_space_clip(C);
1568         MovieClip *clip= ED_space_clip(sc);
1569         Scene *scene= CTX_data_scene(C);
1570         MovieTracking *tracking= &clip->tracking;
1571         MovieTrackingSettings *settings= &clip->tracking.settings;
1572         MovieTrackingObject *object= BKE_tracking_active_object(tracking);
1573         int width, height;
1574
1575         if(!BKE_tracking_can_reconstruct(tracking, object, error_msg, max_error))
1576                 return 0;
1577
1578         /* could fail if footage uses images with different sizes */
1579         BKE_movieclip_get_size(clip, &sc->user, &width, &height);
1580
1581         scj->clip= clip;
1582         scj->scene= scene;
1583         scj->reports= op->reports;
1584         scj->user= sc->user;
1585
1586         scj->context= BKE_tracking_reconstruction_context_new(tracking, object,
1587                         settings->keyframe1, settings->keyframe2, width, height);
1588
1589         tracking->stats= MEM_callocN(sizeof(MovieTrackingStats), "solve camera stats");
1590
1591         return 1;
1592 }
1593
1594 static void solve_camera_updatejob(void *scv)
1595 {
1596         SolveCameraJob *scj= (SolveCameraJob *)scv;
1597         MovieTracking *tracking= &scj->clip->tracking;
1598
1599         BLI_strncpy(tracking->stats->message, scj->stats_message, sizeof(tracking->stats->message));
1600 }
1601
1602 static void solve_camera_startjob(void *scv, short *stop, short *do_update, float *progress)
1603 {
1604         SolveCameraJob *scj= (SolveCameraJob *)scv;
1605
1606         BKE_tracking_solve_reconstruction(scj->context, stop, do_update, progress,
1607                         scj->stats_message, sizeof(scj->stats_message));
1608 }
1609
1610 static void solve_camera_freejob(void *scv)
1611 {
1612         SolveCameraJob *scj= (SolveCameraJob *)scv;
1613         MovieTracking *tracking= &scj->clip->tracking;
1614         Scene *scene= scj->scene;
1615         MovieClip *clip= scj->clip;
1616         int solved;
1617
1618         if(!scj->context) {
1619                 /* job weren't fully initialized due to some error */
1620                 MEM_freeN(scj);
1621                 return;
1622         }
1623
1624         solved= BKE_tracking_finish_reconstruction(scj->context, tracking);
1625
1626         if(!solved)
1627                 BKE_report(scj->reports, RPT_WARNING, "Some data failed to reconstruct, see console for details");
1628         else
1629                 BKE_reportf(scj->reports, RPT_INFO, "Average reprojection error %.3f", tracking->reconstruction.error);
1630
1631         /* set currently solved clip as active for scene */
1632         if(scene->clip)
1633                 id_us_min(&clip->id);
1634
1635         scene->clip= clip;
1636         id_us_plus(&clip->id);
1637
1638         /* set blender camera focal length so result would look fine there */
1639         if(scene->camera) {
1640                 Camera *camera= (Camera*)scene->camera->data;
1641                 int width, height;
1642
1643                 BKE_movieclip_get_size(clip, &scj->user, &width, &height);
1644
1645                 BKE_tracking_camera_to_blender(tracking, scene, camera, width, height);
1646
1647                 WM_main_add_notifier(NC_OBJECT, camera);
1648         }
1649
1650         MEM_freeN(tracking->stats);
1651         tracking->stats= NULL;
1652
1653         DAG_id_tag_update(&clip->id, 0);
1654
1655         WM_main_add_notifier(NC_MOVIECLIP|NA_EVALUATED, clip);
1656         WM_main_add_notifier(NC_OBJECT|ND_TRANSFORM, NULL);
1657
1658         /* update active clip displayed in scene buttons */
1659         WM_main_add_notifier(NC_SCENE, scene);
1660
1661         BKE_tracking_reconstruction_context_free(scj->context);
1662         MEM_freeN(scj);
1663 }
1664
1665 static int solve_camera_exec(bContext *C, wmOperator *op)
1666 {
1667         SolveCameraJob *scj;
1668         char error_msg[256]= "\0";
1669
1670         scj= MEM_callocN(sizeof(SolveCameraJob), "SolveCameraJob data");
1671         if(!solve_camera_initjob(C, scj, op, error_msg, sizeof(error_msg))) {
1672                 if(error_msg[0])
1673                         BKE_report(op->reports, RPT_ERROR, error_msg);
1674
1675                 solve_camera_freejob(scj);
1676
1677                 return OPERATOR_CANCELLED;
1678         }
1679
1680         solve_camera_startjob(scj, NULL, NULL, NULL);
1681
1682         solve_camera_freejob(scj);
1683
1684         return OPERATOR_FINISHED;
1685 }
1686
1687 static int solve_camera_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
1688 {
1689         SolveCameraJob *scj;
1690         ScrArea *sa= CTX_wm_area(C);
1691         SpaceClip *sc= CTX_wm_space_clip(C);
1692         MovieClip *clip= ED_space_clip(sc);
1693         MovieTracking *tracking= &clip->tracking;
1694         MovieTrackingReconstruction *reconstruction= BKE_tracking_get_reconstruction(tracking);
1695         wmJob *steve;
1696         char error_msg[256]= "\0";
1697
1698         if(WM_jobs_test(CTX_wm_manager(C), CTX_wm_area(C))) {
1699                 /* only one solve is allowed at a time */
1700                 return OPERATOR_CANCELLED;
1701         }
1702
1703         scj= MEM_callocN(sizeof(SolveCameraJob), "SolveCameraJob data");
1704         if(!solve_camera_initjob(C, scj, op, error_msg, sizeof(error_msg))) {
1705                 if(error_msg[0])
1706                         BKE_report(op->reports, RPT_ERROR, error_msg);
1707
1708                 solve_camera_freejob(scj);
1709
1710                 return OPERATOR_CANCELLED;
1711         }
1712
1713         BLI_strncpy(tracking->stats->message, "Solving camera | Preparing solve", sizeof(tracking->stats->message));
1714
1715         /* hide reconstruction statistics from previous solve */
1716         reconstruction->flag&= ~TRACKING_RECONSTRUCTED;
1717         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
1718
1719         /* setup job */
1720         steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), sa, "Solve Camera", WM_JOB_PROGRESS);
1721         WM_jobs_customdata(steve, scj, solve_camera_freejob);
1722         WM_jobs_timer(steve, 0.1, NC_MOVIECLIP|NA_EVALUATED, 0);
1723         WM_jobs_callbacks(steve, solve_camera_startjob, NULL, solve_camera_updatejob, NULL);
1724
1725         G.afbreek= 0;
1726
1727         WM_jobs_start(CTX_wm_manager(C), steve);
1728         WM_cursor_wait(0);
1729
1730         /* add modal handler for ESC */
1731         WM_event_add_modal_handler(C, op);
1732
1733         return OPERATOR_RUNNING_MODAL;
1734 }
1735
1736 static int solve_camera_modal(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
1737 {
1738         /* no running solver, remove handler and pass through */
1739         if(0==WM_jobs_test(CTX_wm_manager(C), CTX_wm_area(C)))
1740                 return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
1741
1742         /* running tracking */
1743         switch (event->type) {
1744                 case ESCKEY:
1745                         return OPERATOR_RUNNING_MODAL;
1746                         break;
1747         }
1748
1749         return OPERATOR_PASS_THROUGH;
1750 }
1751
1752 void CLIP_OT_solve_camera(wmOperatorType *ot)
1753 {
1754         /* identifiers */
1755         ot->name= "Solve Camera";
1756         ot->description= "Solve camera motion from tracks";
1757         ot->idname= "CLIP_OT_solve_camera";
1758
1759         /* api callbacks */
1760         ot->exec= solve_camera_exec;
1761         ot->invoke= solve_camera_invoke;
1762         ot->modal= solve_camera_modal;
1763         ot->poll= ED_space_clip_poll;
1764
1765         /* flags */
1766         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1767 }
1768
1769 /********************** clear solution operator *********************/
1770
1771 static int clear_solution_exec(bContext *C, wmOperator *UNUSED(op))
1772 {
1773         SpaceClip *sc= CTX_wm_space_clip(C);
1774         MovieClip *clip= ED_space_clip(sc);
1775         MovieTracking *tracking= &clip->tracking;
1776         ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
1777         MovieTrackingReconstruction *reconstruction= BKE_tracking_get_reconstruction(tracking);
1778         MovieTrackingTrack *track= tracksbase->first;
1779
1780         while(track) {
1781                 track->flag&= ~TRACK_HAS_BUNDLE;
1782
1783                 track= track->next;
1784         }
1785
1786         if(reconstruction->cameras)
1787                 MEM_freeN(reconstruction->cameras);
1788
1789         reconstruction->cameras= NULL;
1790         reconstruction->camnr= 0;
1791
1792         reconstruction->flag&= ~TRACKING_RECONSTRUCTED;
1793
1794         DAG_id_tag_update(&clip->id, 0);
1795
1796         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
1797         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, NULL);
1798
1799         return OPERATOR_FINISHED;
1800 }
1801
1802 void CLIP_OT_clear_solution(wmOperatorType *ot)
1803 {
1804         /* identifiers */
1805         ot->name= "Clear Solution";
1806         ot->description= "Clear all calculated data";
1807         ot->idname= "CLIP_OT_clear_solution";
1808
1809         /* api callbacks */
1810         ot->exec= clear_solution_exec;
1811         ot->poll= ED_space_clip_poll;
1812
1813         /* flags */
1814         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1815 }
1816
1817 /********************** clear track operator *********************/
1818
1819 static int clear_track_path_exec(bContext *C, wmOperator *op)
1820 {
1821         SpaceClip *sc= CTX_wm_space_clip(C);
1822         MovieClip *clip= ED_space_clip(sc);
1823         MovieTrackingTrack *track;
1824         ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
1825         int action= RNA_enum_get(op->ptr, "action");
1826
1827         track= tracksbase->first;
1828         while(track) {
1829                 if(TRACK_VIEW_SELECTED(sc, track))
1830                         BKE_tracking_clear_path(track, sc->user.framenr, action);
1831
1832                 track= track->next;
1833         }
1834
1835         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
1836
1837         return OPERATOR_FINISHED;
1838 }
1839
1840 void CLIP_OT_clear_track_path(wmOperatorType *ot)
1841 {
1842         static EnumPropertyItem clear_path_actions[] = {
1843                         {TRACK_CLEAR_UPTO, "UPTO", 0, "Clear up-to", "Clear path up to current frame"},
1844                         {TRACK_CLEAR_REMAINED, "REMAINED", 0, "Clear remained", "Clear path at remaining frames (after current)"},
1845                         {TRACK_CLEAR_ALL, "ALL", 0, "Clear all", "Clear the whole path"},
1846                         {0, NULL, 0, NULL, NULL}
1847         };
1848
1849         /* identifiers */
1850         ot->name= "Clear Track Path";
1851         ot->description= "Clear tracks after/before current position or clear the whole track";
1852         ot->idname= "CLIP_OT_clear_track_path";
1853
1854         /* api callbacks */
1855         ot->exec= clear_track_path_exec;
1856         ot->poll= ED_space_clip_poll;
1857
1858         /* flags */
1859         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1860
1861         /* proeprties */
1862         RNA_def_enum(ot->srna, "action", clear_path_actions, TRACK_CLEAR_REMAINED, "Action", "Clear action to execute");
1863 }
1864
1865 /********************** disable markers operator *********************/
1866
1867 static int disable_markers_exec(bContext *C, wmOperator *op)
1868 {
1869         SpaceClip *sc= CTX_wm_space_clip(C);
1870         MovieClip *clip= ED_space_clip(sc);
1871         MovieTracking *tracking= &clip->tracking;
1872         ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
1873         MovieTrackingTrack *track= tracksbase->first;
1874         int action= RNA_enum_get(op->ptr, "action");
1875
1876         while(track) {
1877                 if(TRACK_VIEW_SELECTED(sc, track) && (track->flag&TRACK_LOCKED)==0) {
1878                         MovieTrackingMarker *marker= BKE_tracking_ensure_marker(track, sc->user.framenr);
1879
1880                         if(action==0) marker->flag|= MARKER_DISABLED;
1881                         else if(action==1) marker->flag&= ~MARKER_DISABLED;
1882                         else marker->flag^= MARKER_DISABLED;
1883                 }
1884
1885                 track= track->next;
1886         }
1887
1888         DAG_id_tag_update(&clip->id, 0);
1889
1890         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
1891
1892         return OPERATOR_FINISHED;
1893 }
1894
1895 void CLIP_OT_disable_markers(wmOperatorType *ot)
1896 {
1897         static EnumPropertyItem actions_items[] = {
1898                         {0, "DISABLE", 0, "Disable", "Disable selected markers"},
1899                         {1, "ENABLE", 0, "Enable", "Enable selected markers"},
1900                         {2, "TOGGLE", 0, "Toggle", "Toggle disabled flag for selected markers"},
1901                         {0, NULL, 0, NULL, NULL}
1902         };
1903
1904         /* identifiers */
1905         ot->name= "Disable Markers";
1906         ot->description= "Disable/enable selected markers";
1907         ot->idname= "CLIP_OT_disable_markers";
1908
1909         /* api callbacks */
1910         ot->exec= disable_markers_exec;
1911         ot->poll= ED_space_clip_poll;
1912
1913         /* flags */
1914         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1915
1916         /* properties */
1917         RNA_def_enum(ot->srna, "action", actions_items, 0, "Action", "Disable action to execute");
1918 }
1919
1920 /********************** set origin operator *********************/
1921
1922 static Object *get_camera_with_movieclip(Scene *scene, MovieClip *clip)
1923 {
1924         Object *camera= scene->camera;
1925         Base *base;
1926
1927         if(camera && object_get_movieclip(scene, camera, 0)==clip)
1928                 return camera;
1929
1930         base= scene->base.first;
1931         while(base) {
1932                 if(base->object->type == OB_CAMERA) {
1933                         if(object_get_movieclip(scene, base->object, 0)==clip) {
1934                                 camera= base->object;
1935                                 break;
1936                         }
1937                 }
1938
1939                 base= base->next;
1940         }
1941
1942         return camera;
1943 }
1944
1945 static Object *get_orientation_object(bContext *C)
1946 {
1947         Scene *scene= CTX_data_scene(C);
1948         SpaceClip *sc= CTX_wm_space_clip(C);
1949         MovieClip *clip= ED_space_clip(sc);
1950         MovieTracking *tracking= &clip->tracking;
1951         MovieTrackingObject *tracking_object= BKE_tracking_active_object(tracking);
1952         Object *object= NULL;
1953
1954         if(tracking_object->flag&TRACKING_OBJECT_CAMERA) {
1955                 object= get_camera_with_movieclip(scene, clip);
1956         }
1957         else {
1958                 object= OBACT;
1959         }
1960
1961         if(object && object->parent)
1962                 object= object->parent;
1963
1964         return object;
1965 }
1966
1967 static int set_orientation_poll(bContext *C)
1968 {
1969         if(space_clip_frame_poll(C)) {
1970                 Scene *scene= CTX_data_scene(C);
1971                 SpaceClip *sc= CTX_wm_space_clip(C);
1972                 MovieClip *clip= ED_space_clip(sc);
1973                 MovieTracking *tracking= &clip->tracking;
1974                 MovieTrackingObject *tracking_object= BKE_tracking_active_object(tracking);
1975
1976                 if(tracking_object->flag&TRACKING_OBJECT_CAMERA) {
1977                         return 1;
1978                 }
1979                 else {
1980                         return OBACT != NULL;
1981                 }
1982         }
1983
1984         return 0;
1985 }
1986
1987 static int count_selected_bundles(bContext *C)
1988 {
1989         SpaceClip *sc= CTX_wm_space_clip(C);
1990         MovieClip *clip= ED_space_clip(sc);
1991         ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
1992         MovieTrackingTrack *track;
1993         int tot= 0;
1994
1995         track= tracksbase->first;
1996         while(track) {
1997                 if(TRACK_VIEW_SELECTED(sc, track) && (track->flag&TRACK_HAS_BUNDLE))
1998                         tot++;
1999
2000                 track= track->next;
2001         }
2002
2003         return tot;
2004 }
2005
2006 static void object_solver_inverted_matrix(Scene *scene, Object *ob, float invmat[4][4])
2007 {
2008         bConstraint *con;
2009         int found= 0;
2010
2011         for (con= ob->constraints.first; con; con=con->next) {
2012                 bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
2013
2014                 if(!cti)
2015                         continue;
2016
2017                 if(cti->type==CONSTRAINT_TYPE_OBJECTSOLVER) {
2018                         bObjectSolverConstraint *data= (bObjectSolverConstraint *)con->data;
2019
2020                         if(!found) {
2021                                 Object *cam= data->camera ? data->camera : scene->camera;
2022
2023                                 where_is_object_mat(scene, cam, invmat);
2024                         }
2025
2026                         mult_m4_m4m4(invmat, invmat, data->invmat);
2027
2028                         found= 1;
2029                 }
2030         }
2031
2032         if(found)
2033                 invert_m4(invmat);
2034         else
2035                 unit_m4(invmat);
2036 }
2037
2038 static Object *object_solver_camera(Scene *scene, Object *ob)
2039 {
2040         bConstraint *con;
2041
2042         for (con= ob->constraints.first; con; con=con->next) {
2043                 bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
2044
2045                 if(!cti)
2046                         continue;
2047
2048                 if(cti->type==CONSTRAINT_TYPE_OBJECTSOLVER) {
2049                         bObjectSolverConstraint *data= (bObjectSolverConstraint *)con->data;
2050
2051                         return data->camera ? data->camera : scene->camera;
2052                 }
2053         }
2054
2055         return NULL;
2056 }
2057
2058 static int set_origin_exec(bContext *C, wmOperator *op)
2059 {
2060         SpaceClip *sc= CTX_wm_space_clip(C);
2061         MovieClip *clip= ED_space_clip(sc);
2062         MovieTracking *tracking= &clip->tracking;
2063         MovieTrackingTrack *track;
2064         MovieTrackingObject *tracking_object;
2065         Scene *scene= CTX_data_scene(C);
2066         Object *object;
2067         Object *camera= get_camera_with_movieclip(scene, clip);
2068         ListBase *tracksbase;
2069         float mat[4][4], vec[3], median[3];
2070         int selected_count= count_selected_bundles(C);
2071
2072         if(selected_count==0) {
2073                 BKE_report(op->reports, RPT_ERROR, "At least one track with bundle should be selected to define origin position");
2074
2075                 return OPERATOR_CANCELLED;
2076         }
2077
2078         object= get_orientation_object(C);
2079         if(!object) {
2080                 BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
2081
2082                 return OPERATOR_CANCELLED;
2083         }
2084
2085         tracking_object= BKE_tracking_active_object(tracking);
2086
2087         tracksbase= BKE_tracking_object_tracks(tracking, tracking_object);
2088
2089         track= tracksbase->first;
2090         zero_v3(median);
2091         while(track) {
2092                 if(TRACK_VIEW_SELECTED(sc, track) && (track->flag&TRACK_HAS_BUNDLE)) {
2093                         add_v3_v3(median, track->bundle_pos);
2094                 }
2095
2096                 track= track->next;
2097         }
2098         mul_v3_fl(median, 1.0f/selected_count);
2099
2100         BKE_get_tracking_mat(scene, camera, mat);
2101
2102         mul_v3_m4v3(vec, mat, median);
2103
2104         if(tracking_object->flag&TRACKING_OBJECT_CAMERA) {
2105                 sub_v3_v3(object->loc, vec);
2106         }
2107         else {
2108                 object_solver_inverted_matrix(scene, object, mat);
2109                 mul_v3_m4v3(vec, mat, vec);
2110                 copy_v3_v3(object->loc, vec);
2111         }
2112
2113         DAG_id_tag_update(&clip->id, 0);
2114         DAG_id_tag_update(&object->id, OB_RECALC_OB);
2115
2116         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
2117         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
2118
2119         return OPERATOR_FINISHED;
2120 }
2121
2122 void CLIP_OT_set_origin(wmOperatorType *ot)
2123 {
2124         /* identifiers */
2125         ot->name= "Set Origin";
2126         ot->description= "Set active marker as origin by moving camera (or it's parent if present) in 3D space";
2127         ot->idname= "CLIP_OT_set_origin";
2128
2129         /* api callbacks */
2130         ot->exec= set_origin_exec;
2131         ot->poll= set_orientation_poll;
2132
2133         /* flags */
2134         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2135
2136         /* properties */
2137         RNA_def_boolean(ot->srna, "use_median", 0, "Use Median", "Set origin to median point of selected bundles");
2138 }
2139
2140 /********************** set floor operator *********************/
2141
2142 static void set_axis(Scene *scene,  Object *ob, MovieClip *clip, MovieTrackingObject *tracking_object,
2143                         MovieTrackingTrack *track, char axis)
2144 {
2145         Object *camera= get_camera_with_movieclip(scene, clip);
2146         int is_camera= tracking_object->flag&TRACKING_OBJECT_CAMERA;
2147         int  flip= 0;
2148         float mat[4][4], vec[3], obmat[4][4], dvec[3];
2149
2150         object_to_mat4(ob, obmat);
2151
2152         BKE_get_tracking_mat(scene, camera, mat);
2153         mul_v3_m4v3(vec, mat, track->bundle_pos);
2154         copy_v3_v3(dvec, vec);
2155
2156         if(!is_camera) {
2157                 float imat[4][4];
2158
2159                 object_solver_inverted_matrix(scene, ob, imat);
2160                 mul_v3_m4v3(vec, imat, vec);
2161
2162                 invert_m4_m4(imat, obmat);
2163                 mul_v3_m4v3(dvec, imat, vec);
2164
2165                 sub_v3_v3(vec, obmat[3]);
2166         }
2167
2168         if(len_v2(vec) < 1e-3f)
2169                 return;
2170
2171         unit_m4(mat);
2172
2173         if(axis=='X') {
2174                 if(fabsf(dvec[1])<1e-3f) {
2175                         flip= 1;
2176
2177                         mat[0][0]= -1.0f; mat[0][1]= 0.0f; mat[0][2]= 0.0f;
2178                         mat[1][0]= 0.0f; mat[1][1]= -1.0f; mat[1][2]= 0.0f;
2179                         mat[2][0]= 0.0f; mat[2][1]= 0.0f; mat[2][2]= 1.0f;
2180                 } else {
2181                         copy_v3_v3(mat[0], vec);
2182
2183                         if(is_camera || fabsf(vec[2])<1e-3f) {
2184                                 mat[0][2]= 0.0f;
2185                                 mat[2][0]= 0.0f; mat[2][1]= 0.0f; mat[2][2]= 1.0f;
2186                                 cross_v3_v3v3(mat[1], mat[2], mat[0]);
2187                         }
2188                         else {
2189                                 vec[2]= 0.0f;
2190
2191                                 cross_v3_v3v3(mat[1], mat[0], vec);
2192                                 cross_v3_v3v3(mat[2], mat[0], mat[1]);
2193                         }
2194                 }
2195         } else {
2196                 if(fabsf(dvec[0])<1e-3f) {
2197                         flip= 1;
2198
2199                         mat[0][0]= -1.0f; mat[0][1]= 0.0f; mat[0][2]= 0.0f;
2200                         mat[1][0]= 0.0f; mat[1][1]= -1.0f; mat[1][2]= 0.0f;
2201                         mat[2][0]= 0.0f; mat[2][1]= 0.0f; mat[2][2]= 1.0f;
2202                 } else {
2203                         copy_v3_v3(mat[1], vec);
2204
2205                         if(is_camera || fabsf(vec[2])<1e-3f) {
2206                                 mat[1][2]= 0.0f;
2207                                 mat[2][0]= 0.0f; mat[2][1]= 0.0f; mat[2][2]= 1.0f;
2208                                 cross_v3_v3v3(mat[0], mat[1], mat[2]);
2209                         }
2210                         else {
2211                                 vec[2]= 0.0f;
2212
2213                                 cross_v3_v3v3(mat[0], vec, mat[1]);
2214                                 cross_v3_v3v3(mat[2], mat[0], mat[1]);
2215                         }
2216                 }
2217         }
2218
2219         normalize_v3(mat[0]);
2220         normalize_v3(mat[1]);
2221         normalize_v3(mat[2]);
2222
2223         if(is_camera) {
2224                 invert_m4(mat);
2225
2226                 mult_m4_m4m4(mat, mat, obmat);
2227         }
2228         else {
2229                 if(!flip) {
2230                         float lmat[4][4], ilmat[4][4], rmat[3][3];
2231
2232                         object_rot_to_mat3(ob, rmat);
2233                         invert_m3(rmat);
2234                         mul_m4_m4m3(mat, mat, rmat);
2235
2236                         unit_m4(lmat);
2237                         copy_v3_v3(lmat[3], obmat[3]);
2238                         invert_m4_m4(ilmat, lmat);
2239
2240                         mul_serie_m4(mat, lmat, mat, ilmat, obmat, NULL, NULL, NULL, NULL);
2241                 }
2242                 else {
2243                         mult_m4_m4m4(mat, obmat, mat);
2244                 }
2245         }
2246
2247         object_apply_mat4(ob, mat, 0, 0);
2248 }
2249
2250 static int set_floor_exec(bContext *C, wmOperator *op)
2251 {
2252         SpaceClip *sc= CTX_wm_space_clip(C);
2253         MovieClip *clip= ED_space_clip(sc);
2254         Scene *scene= CTX_data_scene(C);
2255         MovieTracking *tracking= &clip->tracking;
2256         MovieTrackingObject *tracking_object;
2257         MovieTrackingTrack *track, *axis_track= NULL, *act_track;
2258         ListBase *tracksbase;
2259         Object *object;
2260         Object *camera= get_camera_with_movieclip(scene, clip);
2261         int tot= 0;
2262         float vec[3][3], mat[4][4], obmat[4][4], newmat[4][4], orig[3]= {0.0f, 0.0f, 0.0f};
2263         float rot[4][4]={{0.0f, 0.0f, -1.0f, 0.0f},
2264                          {0.0f, 1.0f, 0.0f, 0.0f},
2265                          {1.0f, 0.0f, 0.0f, 0.0f},
2266                          {0.0f, 0.0f, 0.0f, 1.0f}};     /* 90 degrees Y-axis rotation matrix */
2267
2268         if(count_selected_bundles(C)!=3) {
2269                 BKE_report(op->reports, RPT_ERROR, "Three tracks with bundles are needed to orient the floor");
2270
2271                 return OPERATOR_CANCELLED;
2272         }
2273
2274         tracking_object= BKE_tracking_active_object(tracking);
2275         tracksbase= BKE_tracking_object_tracks(tracking, tracking_object);
2276         act_track= BKE_tracking_active_track(tracking);
2277
2278         object= get_orientation_object(C);
2279         if(!object) {
2280                 BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
2281
2282                 return OPERATOR_CANCELLED;
2283         }
2284
2285         BKE_get_tracking_mat(scene, camera, mat);
2286
2287         /* get 3 bundles to use as reference */
2288         track= tracksbase->first;
2289         while(track && tot<3) {
2290                 if(track->flag&TRACK_HAS_BUNDLE && TRACK_VIEW_SELECTED(sc, track)) {
2291                         mul_v3_m4v3(vec[tot], mat, track->bundle_pos);
2292
2293                         if(tot==0 || track==act_track)
2294                                 copy_v3_v3(orig, vec[tot]);
2295                         else
2296                                 axis_track= track;
2297
2298                         tot++;
2299                 }
2300
2301                 track= track->next;
2302         }
2303
2304         sub_v3_v3(vec[1], vec[0]);
2305         sub_v3_v3(vec[2], vec[0]);
2306
2307         /* construct ortho-normal basis */
2308         unit_m4(mat);
2309
2310         cross_v3_v3v3(mat[0], vec[1], vec[2]);
2311         copy_v3_v3(mat[1], vec[1]);
2312         cross_v3_v3v3(mat[2], mat[0], mat[1]);
2313
2314         normalize_v3(mat[0]);
2315         normalize_v3(mat[1]);
2316         normalize_v3(mat[2]);
2317
2318         /* move to origin point */
2319         mat[3][0]= orig[0];
2320         mat[3][1]= orig[1];
2321         mat[3][2]= orig[2];
2322
2323         if(tracking_object->flag&TRACKING_OBJECT_CAMERA) {
2324                 invert_m4(mat);
2325
2326                 object_to_mat4(object, obmat);
2327                 mult_m4_m4m4(mat, mat, obmat);
2328                 mult_m4_m4m4(newmat, rot, mat);
2329                 object_apply_mat4(object, newmat, 0, 0);
2330
2331                 /* make camera have positive z-coordinate */
2332                 if(object->loc[2]<0) {
2333                         invert_m4(rot);
2334                         mult_m4_m4m4(newmat, rot, mat);
2335                         object_apply_mat4(object, newmat, 0, 0);
2336                 }
2337         }
2338         else {
2339                 object_apply_mat4(object, mat, 0, 0);
2340         }
2341
2342         where_is_object(scene, object);
2343         set_axis(scene, object, clip, tracking_object, axis_track, 'X');
2344
2345         DAG_id_tag_update(&clip->id, 0);
2346         DAG_id_tag_update(&object->id, OB_RECALC_OB);
2347
2348         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
2349         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
2350
2351         return OPERATOR_FINISHED;
2352 }
2353
2354 void CLIP_OT_set_floor(wmOperatorType *ot)
2355 {
2356         /* identifiers */
2357         ot->name= "Set Floor";
2358         ot->description= "Set floor based on 3 selected bundles by moving camera (or it's parent if present) in 3D space";
2359         ot->idname= "CLIP_OT_set_floor";
2360
2361         /* api callbacks */
2362         ot->exec= set_floor_exec;
2363         ot->poll= set_orientation_poll;
2364
2365         /* flags */
2366         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2367 }
2368
2369 /********************** set axis operator *********************/
2370
2371 static int set_axis_exec(bContext *C, wmOperator *op)
2372 {
2373         SpaceClip *sc= CTX_wm_space_clip(C);
2374         MovieClip *clip= ED_space_clip(sc);
2375         MovieTracking *tracking= &clip->tracking;
2376         MovieTrackingObject *tracking_object= BKE_tracking_active_object(tracking);
2377         MovieTrackingTrack *track;
2378         Scene *scene= CTX_data_scene(C);
2379         Object *object;
2380         ListBase *tracksbase;
2381         int axis= RNA_enum_get(op->ptr, "axis");
2382
2383         if(count_selected_bundles(C)!=1) {
2384                 BKE_report(op->reports, RPT_ERROR, "Single track with bundle should be selected to define axis");
2385
2386                 return OPERATOR_CANCELLED;
2387         }
2388
2389         object= get_orientation_object(C);
2390         if(!object) {
2391                 BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
2392
2393                 return OPERATOR_CANCELLED;
2394         }
2395
2396         tracksbase= BKE_tracking_object_tracks(tracking, tracking_object);
2397
2398         track=tracksbase->first;
2399         while(track) {
2400                 if(TRACK_VIEW_SELECTED(sc, track))
2401                         break;
2402
2403                 track= track->next;
2404         }
2405
2406         set_axis(scene, object, clip, tracking_object, track, axis==0?'X':'Y');
2407
2408         DAG_id_tag_update(&clip->id, 0);
2409         DAG_id_tag_update(&object->id, OB_RECALC_OB);
2410
2411         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
2412         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
2413
2414         return OPERATOR_FINISHED;
2415 }
2416
2417 void CLIP_OT_set_axis(wmOperatorType *ot)
2418 {
2419         static EnumPropertyItem axis_actions[] = {
2420                         {0, "X", 0, "X", "Align bundle align X axis"},
2421                         {1, "Y", 0, "Y", "Align bundle align Y axis"},
2422                         {0, NULL, 0, NULL, NULL}
2423         };
2424
2425         /* identifiers */
2426         ot->name= "Set Axis";
2427         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";
2428         ot->idname= "CLIP_OT_set_axis";
2429
2430         /* api callbacks */
2431         ot->exec= set_axis_exec;
2432         ot->poll= set_orientation_poll;
2433
2434         /* flags */
2435         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2436
2437         /* properties */
2438         RNA_def_enum(ot->srna, "axis", axis_actions, 0, "Axis", "Axis to use to align bundle along");
2439 }
2440
2441 /********************** set scale operator *********************/
2442
2443 static int do_set_scale(bContext *C, wmOperator *op, int scale_solution)
2444 {
2445         SpaceClip *sc= CTX_wm_space_clip(C);
2446         MovieClip *clip= ED_space_clip(sc);
2447         MovieTracking *tracking= &clip->tracking;
2448         MovieTrackingObject *tracking_object= BKE_tracking_active_object(tracking);
2449         MovieTrackingTrack *track;
2450         Scene *scene= CTX_data_scene(C);
2451         Object *object= NULL;
2452         Object *camera= get_camera_with_movieclip(scene, clip);
2453         ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
2454         int tot= 0;
2455         float vec[2][3], mat[4][4], scale;
2456         float dist= RNA_float_get(op->ptr, "distance");
2457
2458         if(count_selected_bundles(C)!=2) {
2459                 BKE_report(op->reports, RPT_ERROR, "Two tracks with bundles should be selected to set scale");
2460
2461                 return OPERATOR_CANCELLED;
2462         }
2463
2464         object= get_orientation_object(C);
2465         if(!object) {
2466                 BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
2467
2468                 return OPERATOR_CANCELLED;
2469         }
2470
2471         BKE_get_tracking_mat(scene, camera, mat);
2472
2473         track= tracksbase->first;
2474         while(track) {
2475                 if(TRACK_VIEW_SELECTED(sc, track)) {
2476                         mul_v3_m4v3(vec[tot], mat, track->bundle_pos);
2477                         tot++;
2478                 }
2479
2480                 track= track->next;
2481         }
2482
2483         sub_v3_v3(vec[0], vec[1]);
2484
2485         if(len_v3(vec[0])>1e-5f) {
2486                 scale= dist / len_v3(vec[0]);
2487
2488                 if(tracking_object->flag&TRACKING_OBJECT_CAMERA) {
2489                         mul_v3_fl(object->size, scale);
2490                         mul_v3_fl(object->loc, scale);
2491                 }
2492                 else if(!scale_solution){
2493                         Object *solver_camera= object_solver_camera(scene, object);
2494
2495                         object->size[0]= object->size[1]= object->size[2]= 1.0f/scale;
2496
2497                         if(solver_camera) {
2498                                 object->size[0]/= solver_camera->size[0];
2499                                 object->size[1]/= solver_camera->size[1];
2500                                 object->size[2]/= solver_camera->size[2];
2501                         }
2502                 }
2503                 else {
2504                         tracking_object->scale= scale;
2505                 }
2506
2507                 DAG_id_tag_update(&clip->id, 0);
2508
2509                 if(object)
2510                         DAG_id_tag_update(&object->id, OB_RECALC_OB);
2511
2512                 WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
2513                 WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
2514         }
2515
2516         return OPERATOR_FINISHED;
2517 }
2518
2519 static int set_scale_exec(bContext *C, wmOperator *op)
2520 {
2521         return do_set_scale(C, op, 0);
2522 }
2523
2524 static int set_scale_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
2525 {
2526         SpaceClip *sc= CTX_wm_space_clip(C);
2527         MovieClip *clip= ED_space_clip(sc);
2528
2529         if(!RNA_struct_property_is_set(op->ptr, "distance"))
2530                 RNA_float_set(op->ptr, "distance", clip->tracking.settings.dist);
2531
2532         return set_scale_exec(C, op);
2533 }
2534
2535 void CLIP_OT_set_scale(wmOperatorType *ot)
2536 {
2537         /* identifiers */
2538         ot->name= "Set Scale";
2539         ot->description= "Set scale of scene by scaling camera (or it's parent if present)";
2540         ot->idname= "CLIP_OT_set_scale";
2541
2542         /* api callbacks */
2543         ot->exec= set_scale_exec;
2544         ot->invoke= set_scale_invoke;
2545         ot->poll= set_orientation_poll;
2546
2547         /* flags */
2548         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2549
2550         /* properties */
2551         RNA_def_float(ot->srna, "distance", 0.0f, -FLT_MAX, FLT_MAX,
2552                 "Distance", "Distance between selected tracks", -100.0f, 100.0f);
2553 }
2554
2555 /********************** set solution scale operator *********************/
2556
2557 static int set_solution_scale_poll(bContext *C)
2558 {
2559         if(space_clip_frame_poll(C)) {
2560                 SpaceClip *sc= CTX_wm_space_clip(C);
2561                 MovieClip *clip= ED_space_clip(sc);
2562                 MovieTracking *tracking= &clip->tracking;
2563                 MovieTrackingObject *tracking_object= BKE_tracking_active_object(tracking);
2564
2565                 return (tracking_object->flag&TRACKING_OBJECT_CAMERA) == 0;
2566         }
2567
2568         return 0;
2569 }
2570
2571 static int set_solution_scale_exec(bContext *C, wmOperator *op)
2572 {
2573         return do_set_scale(C, op, 1);
2574 }
2575
2576 static int set_solution_scale_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
2577 {
2578         SpaceClip *sc= CTX_wm_space_clip(C);
2579         MovieClip *clip= ED_space_clip(sc);
2580
2581         if(!RNA_struct_property_is_set(op->ptr, "distance"))
2582                 RNA_float_set(op->ptr, "distance", clip->tracking.settings.object_distance);
2583
2584         return set_solution_scale_exec(C, op);
2585 }
2586
2587 void CLIP_OT_set_solution_scale(wmOperatorType *ot)
2588 {
2589         /* identifiers */
2590         ot->name= "Set Solution Scale";
2591         ot->description= "Set object solution scale using distance between two selected tracks";
2592         ot->idname= "CLIP_OT_set_solution_scale";
2593
2594         /* api callbacks */
2595         ot->exec= set_solution_scale_exec;
2596         ot->invoke= set_solution_scale_invoke;
2597         ot->poll= set_solution_scale_poll;
2598
2599         /* flags */
2600         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2601
2602         /* properties */
2603         RNA_def_float(ot->srna, "distance", 0.0f, -FLT_MAX, FLT_MAX,
2604                 "Distance", "Distance between selected tracks", -100.0f, 100.0f);
2605 }
2606
2607 /********************** set principal center operator *********************/
2608
2609 static int set_center_principal_exec(bContext *C, wmOperator *UNUSED(op))
2610 {
2611         SpaceClip *sc= CTX_wm_space_clip(C);
2612         MovieClip *clip= ED_space_clip(sc);
2613         int width, height;
2614
2615         BKE_movieclip_get_size(clip, &sc->user, &width, &height);
2616
2617         if(width==0 || height==0)
2618                 return OPERATOR_CANCELLED;
2619
2620         clip->tracking.camera.principal[0]= ((float)width)/2.0f;
2621         clip->tracking.camera.principal[1]= ((float)height)/2.0f;
2622
2623         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, clip);
2624
2625         return OPERATOR_FINISHED;
2626 }
2627
2628 void CLIP_OT_set_center_principal(wmOperatorType *ot)
2629 {
2630         /* identifiers */
2631         ot->name= "Set Principal to Center";
2632         ot->description= "Set optical center to center of footage";
2633         ot->idname= "CLIP_OT_set_center_principal";
2634
2635         /* api callbacks */
2636         ot->exec= set_center_principal_exec;
2637         ot->poll= ED_space_clip_poll;
2638
2639         /* flags */
2640         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2641 }
2642
2643 /********************** hide tracks operator *********************/
2644
2645 static int hide_tracks_exec(bContext *C, wmOperator *op)
2646 {
2647         SpaceClip *sc= CTX_wm_space_clip(C);
2648         MovieClip *clip= ED_space_clip(sc);
2649         MovieTrackingTrack *track;
2650         MovieTracking *tracking= &clip->tracking;
2651         ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
2652         MovieTrackingTrack *act_track= BKE_tracking_active_track(tracking);
2653         int unselected;
2654
2655         unselected= RNA_boolean_get(op->ptr, "unselected");
2656
2657         track= tracksbase->first;
2658         while(track) {
2659                 if(unselected==0 && TRACK_VIEW_SELECTED(sc, track)) {
2660                         track->flag|= TRACK_HIDDEN;
2661                 } else if(unselected==1 && !TRACK_VIEW_SELECTED(sc, track)) {
2662                         track->flag|= TRACK_HIDDEN;
2663                 }
2664
2665                 track= track->next;
2666         }
2667
2668         if(act_track && act_track->flag&TRACK_HIDDEN)
2669                 clip->tracking.act_track= NULL;
2670
2671         if(unselected==0) {
2672                 /* no selection on screen now, unlock view so it can be scrolled nice again */
2673                 sc->flag&= ~SC_LOCK_SELECTION;
2674         }
2675
2676         WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, NULL);
2677
2678         return OPERATOR_FINISHED;
2679 }
2680
2681 void CLIP_OT_hide_tracks(wmOperatorType *ot)
2682 {
2683         /* identifiers */
2684         ot->name= "Hide Tracks";
2685         ot->description= "Hide selected tracks";
2686         ot->idname= "CLIP_OT_hide_tracks";
2687
2688         /* api callbacks */
2689         ot->exec= hide_tracks_exec;
2690         ot->poll= ED_space_clip_poll;
2691
2692         /* flags */
2693         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2694
2695         /* properties */
2696         RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected tracks");
2697 }
2698
2699 /********************** hide tracks clear operator *********************/
2700
2701 static int hide_tracks_clear_exec(bContext *C, wmOperator *UNUSED(op))
2702 {
2703         SpaceClip *sc= CTX_wm_space_clip(C);
2704         MovieClip *clip= ED_space_clip(sc);
2705         ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
2706         MovieTrackingTrack *track;
2707
2708         track= tracksbase->first;
2709         while(track) {
2710                 track->flag&= ~TRACK_HIDDEN;
2711
2712                 track= track->next;
2713         }
2714
2715         WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, NULL);
2716
2717         return OPERATOR_FINISHED;
2718 }
2719
2720 void CLIP_OT_hide_tracks_clear(wmOperatorType *ot)
2721 {
2722         /* identifiers */
2723         ot->name= "Hide Tracks Clear";
2724         ot->description= "Clear hide selected tracks";
2725         ot->idname= "CLIP_OT_hide_tracks_clear";
2726
2727         /* api callbacks */
2728         ot->exec= hide_tracks_clear_exec;
2729         ot->poll= ED_space_clip_poll;
2730
2731         /* flags */
2732         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2733 }
2734
2735 /********************** detect features operator *********************/
2736
2737 static bGPDlayer *detect_get_layer(MovieClip *clip)
2738 {
2739         bGPDlayer *layer;
2740
2741         if(!clip->gpd)
2742                 return NULL;
2743
2744         layer= clip->gpd->layers.first;
2745         while(layer) {
2746                 if(layer->flag&GP_LAYER_ACTIVE)
2747                         return layer;
2748
2749                 layer= layer->next;
2750         }
2751
2752         return NULL;
2753 }
2754
2755 static int detect_features_exec(bContext *C, wmOperator *op)
2756 {
2757         SpaceClip *sc= CTX_wm_space_clip(C);
2758         MovieClip *clip= ED_space_clip(sc);
2759         int clip_flag= clip->flag&MCLIP_TIMECODE_FLAGS;
2760         ImBuf *ibuf= BKE_movieclip_get_ibuf_flag(clip, &sc->user, clip_flag, MOVIECLIP_CACHE_SKIP);
2761         MovieTracking *tracking= &clip->tracking;
2762         ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
2763         MovieTrackingTrack *track= tracksbase->first;
2764         int placement= RNA_enum_get(op->ptr, "placement");
2765         int margin= RNA_int_get(op->ptr, "margin");
2766         int min_trackability= RNA_int_get(op->ptr, "min_trackability");
2767         int min_distance= RNA_int_get(op->ptr, "min_distance");
2768         int place_outside_layer= 0;
2769         bGPDlayer *layer= NULL;
2770
2771         if(placement!=0) {
2772                 layer= detect_get_layer(clip);
2773                 place_outside_layer= placement==2;
2774         }
2775
2776         /* deselect existing tracks */
2777         while(track) {
2778                 track->flag&= ~SELECT;
2779                 track->pat_flag&= ~SELECT;
2780                 track->search_flag&= ~SELECT;
2781
2782                 track= track->next;
2783         }
2784
2785         BKE_tracking_detect_fast(tracking, tracksbase, ibuf, sc->user.framenr, margin,
2786                                 min_trackability, min_distance, layer, place_outside_layer);
2787
2788         IMB_freeImBuf(ibuf);
2789
2790         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, NULL);
2791
2792         return OPERATOR_FINISHED;
2793 }
2794
2795 void CLIP_OT_detect_features(wmOperatorType *ot)
2796 {
2797         static EnumPropertyItem placement_items[] = {
2798                         {0, "FRAME",                    0, "Whole Frame",                       "Place markers across the whole frame"},
2799                         {1, "INSIDE_GPENCIL",   0, "Inside grease pencil",      "Place markers only inside areas outlined with grease pencil"},
2800                         {2, "OUTSIDE_GPENCIL",  0, "Outside grease pencil",     "Place markers only outside areas outlined with grease pencil"},
2801                         {0, NULL, 0, NULL, NULL}
2802         };
2803
2804         /* identifiers */
2805         ot->name= "Detect Features";
2806         ot->description= "Automatically detect features and place markers to track";
2807         ot->idname= "CLIP_OT_detect_features";
2808
2809         /* api callbacks */
2810         ot->exec= detect_features_exec;
2811         ot->poll= space_clip_frame_poll;
2812
2813         /* flags */
2814         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2815
2816         /* properties */
2817         RNA_def_enum(ot->srna, "placement", placement_items, 0, "Placement", "Placement for detected features");
2818         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);
2819         RNA_def_int(ot->srna, "min_trackability", 16, 0, INT_MAX, "Trackability", "Minimum trackability score to add a corner", 0, 300);
2820         RNA_def_int(ot->srna, "min_distance", 120, 0, INT_MAX, "Distance", "Minimal distance accepted between two corners", 0, 300);
2821 }
2822
2823 /********************** frame jump operator *********************/
2824
2825 static int frame_jump_exec(bContext *C, wmOperator *op)
2826 {
2827         Scene *scene= CTX_data_scene(C);
2828         SpaceClip *sc= CTX_wm_space_clip(C);
2829         MovieClip *clip= ED_space_clip(sc);
2830         MovieTrackingTrack *track;
2831         int pos= RNA_enum_get(op->ptr, "position");
2832         int delta;
2833
2834         if(pos<=1) {    /* jump to path */
2835                 track= BKE_tracking_active_track(&clip->tracking);
2836
2837                 if(!track)
2838                         return OPERATOR_CANCELLED;
2839
2840                 delta= pos == 1 ? 1 : -1;
2841
2842                 while(sc->user.framenr+delta >= SFRA && sc->user.framenr+delta <= EFRA) {
2843                         MovieTrackingMarker *marker= BKE_tracking_exact_marker(track, sc->user.framenr+delta);
2844
2845                         if(!marker || marker->flag&MARKER_DISABLED)
2846                                 break;
2847
2848                         sc->user.framenr+= delta;
2849                 }
2850         }
2851         else {  /* to to failed frame */
2852                 if(clip->tracking.reconstruction.flag&TRACKING_RECONSTRUCTED) {
2853                         int a= sc->user.framenr;
2854                         MovieTracking *tracking= &clip->tracking;
2855                         MovieTrackingObject *object= BKE_tracking_active_object(tracking);
2856
2857                         delta= pos == 3 ? 1 : -1;
2858
2859                         a+= delta;
2860
2861                         while(a+delta >= SFRA && a+delta <= EFRA) {
2862                                 MovieReconstructedCamera *cam;
2863
2864                                 cam= BKE_tracking_get_reconstructed_camera(tracking, object, a);
2865
2866                                 if(!cam) {
2867                                         sc->user.framenr= a;
2868
2869                                         break;
2870                                 }
2871
2872                                 a+= delta;
2873                         }
2874                 }
2875         }
2876
2877         if(CFRA!=sc->user.framenr) {
2878                 CFRA= sc->user.framenr;
2879                 sound_seek_scene(CTX_data_main(C), CTX_data_scene(C));
2880
2881                 WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
2882         }
2883
2884         WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, NULL);
2885
2886         return OPERATOR_FINISHED;
2887 }
2888
2889 void CLIP_OT_frame_jump(wmOperatorType *ot)
2890 {
2891         static EnumPropertyItem position_items[] = {
2892                         {0, "PATHSTART",        0, "Path Start",                "Jump to start of current path"},
2893                         {1, "PATHEND",          0, "Path End",                  "Jump to end of current path"},
2894                         {2, "FAILEDPREV",       0, "Previous Failed",   "Jump to previous failed frame"},
2895                         {2, "FAILNEXT",         0, "Next Failed",               "Jump to next failed frame"},
2896                         {0, NULL, 0, NULL, NULL}
2897         };
2898
2899         /* identifiers */
2900         ot->name= "Jump to Frame";
2901         ot->description= "Jump to special frame";
2902         ot->idname= "CLIP_OT_frame_jump";
2903
2904         /* api callbacks */
2905         ot->exec= frame_jump_exec;
2906         ot->poll= space_clip_frame_poll;
2907
2908         /* flags */
2909         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2910
2911         /* properties */
2912         RNA_def_enum(ot->srna, "position", position_items, 0, "Position", "Position to jumo to");
2913 }
2914
2915 /********************** join tracks operator *********************/
2916
2917 static int join_tracks_exec(bContext *C, wmOperator *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 *act_track, *track, *next;
2924
2925         act_track= BKE_tracking_active_track(tracking);
2926
2927         if(!act_track) {
2928                 BKE_report(op->reports, RPT_ERROR, "No active track to join to");
2929                 return OPERATOR_CANCELLED;
2930         }
2931
2932         track= tracksbase->first;
2933         while(track) {
2934                 if(TRACK_VIEW_SELECTED(sc, track) && track!=act_track) {
2935                         if(!BKE_tracking_test_join_tracks(act_track, track)) {
2936                                 BKE_report(op->reports, RPT_ERROR, "Some selected tracks have got keyframed markers to the same frame");
2937                                 return OPERATOR_CANCELLED;
2938                         }
2939                 }
2940
2941                 track= track->next;
2942         }
2943
2944         track= tracksbase->first;
2945         while(track) {
2946                 next= track->next;
2947
2948                 if(TRACK_VIEW_SELECTED(sc, track) && track!=act_track) {
2949                         BKE_tracking_join_tracks(act_track, track);
2950
2951                         BKE_tracking_free_track(track);
2952                         BLI_freelinkN(tracksbase, track);
2953                 }
2954
2955                 track= next;
2956         }
2957
2958         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, clip);
2959
2960         return OPERATOR_FINISHED;
2961 }
2962
2963 void CLIP_OT_join_tracks(wmOperatorType *ot)
2964 {
2965         /* identifiers */
2966         ot->name= "Join Tracks";
2967         ot->description= "Join selected tracks";
2968         ot->idname= "CLIP_OT_join_tracks";
2969
2970         /* api callbacks */
2971         ot->exec= join_tracks_exec;
2972         ot->poll= space_clip_frame_poll;
2973
2974         /* flags */
2975         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2976 }
2977
2978 /********************** lock tracks operator *********************/
2979
2980 static int lock_tracks_exec(bContext *C, wmOperator *op)
2981 {
2982         SpaceClip *sc= CTX_wm_space_clip(C);
2983         MovieClip *clip= ED_space_clip(sc);
2984         MovieTracking *tracking= &clip->tracking;
2985         ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
2986         MovieTrackingTrack *track= tracksbase->first;
2987         int action= RNA_enum_get(op->ptr, "action");
2988
2989         while(track) {
2990                 if(TRACK_VIEW_SELECTED(sc, track)) {
2991                         if(action==0) track->flag|= TRACK_LOCKED;
2992                         else if(action==1) track->flag&= ~TRACK_LOCKED;
2993                         else track->flag^= TRACK_LOCKED;
2994                 }
2995
2996                 track= track->next;
2997         }
2998
2999         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
3000
3001         return OPERATOR_FINISHED;
3002 }
3003
3004 void CLIP_OT_lock_tracks(wmOperatorType *ot)
3005 {
3006         static EnumPropertyItem actions_items[] = {
3007                         {0, "LOCK", 0, "Lock", "Lock selected tracks"},
3008                         {1, "UNLOCK", 0, "Unlock", "Unlock selected tracks"},
3009                         {2, "TOGGLE", 0, "Toggle", "Toggle locked flag for selected tracks"},
3010                         {0, NULL, 0, NULL, NULL}
3011         };
3012
3013         /* identifiers */
3014         ot->name= "Lock Tracks";
3015         ot->description= "Lock/unlock selected tracks";
3016         ot->idname= "CLIP_OT_lock_tracks";
3017
3018         /* api callbacks */
3019         ot->exec= lock_tracks_exec;
3020         ot->poll= ED_space_clip_poll;
3021
3022         /* flags */
3023         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
3024
3025         /* properties */
3026         RNA_def_enum(ot->srna, "action", actions_items, 0, "Action", "Lock action to execute");
3027 }
3028
3029 /********************** track copy color operator *********************/
3030
3031 static int track_copy_color_exec(bContext *C, wmOperator *UNUSED(op))
3032 {
3033         SpaceClip *sc= CTX_wm_space_clip(C);
3034         MovieClip *clip= ED_space_clip(sc);
3035         MovieTracking *tracking= &clip->tracking;
3036         ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
3037         MovieTrackingTrack *track, *act_track= BKE_tracking_active_track(tracking);
3038
3039         if(!act_track)
3040                 return OPERATOR_CANCELLED;
3041
3042         track= tracksbase->first;
3043         while(track) {
3044                 if(TRACK_VIEW_SELECTED(sc, track) && track!=act_track) {
3045                         track->flag&= ~TRACK_CUSTOMCOLOR;
3046
3047                         if(act_track->flag&TRACK_CUSTOMCOLOR) {
3048                                 copy_v3_v3(track->color, act_track->color);
3049                                 track->flag|= TRACK_CUSTOMCOLOR;
3050                         }
3051                 }
3052
3053                 track= track->next;
3054         }
3055
3056         WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, clip);
3057
3058         return OPERATOR_FINISHED;
3059 }
3060
3061 void CLIP_OT_track_copy_color(wmOperatorType *ot)
3062 {
3063         /* identifiers */
3064         ot->name= "Copy Color";
3065         ot->description= "Copy color to all selected tracks";
3066         ot->idname= "CLIP_OT_track_copy_color";
3067
3068         /* api callbacks */
3069         ot->exec= track_copy_color_exec;
3070         ot->poll= ED_space_clip_poll;
3071
3072         /* flags */
3073         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
3074 }
3075
3076 /********************** add 2d stabilization tracks operator *********************/
3077
3078 static int stabilize_2d_add_exec(bContext *C, wmOperator *UNUSED(op))
3079 {
3080         SpaceClip *sc= CTX_wm_space_clip(C);
3081         MovieClip *clip= ED_space_clip(sc);
3082         MovieTracking *tracking= &clip->tracking;
3083         ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
3084         MovieTrackingTrack *track;
3085         MovieTrackingStabilization *stab= &tracking->stabilization;
3086         int update= 0;
3087
3088         track= tracksbase->first;
3089         while(track) {
3090                 if(TRACK_VIEW_SELECTED(sc, track) && (track->flag&TRACK_USE_2D_STAB)==0) {
3091                         track->flag|= TRACK_USE_2D_STAB;
3092                         stab->tot_track++;
3093
3094                         update= 1;
3095                 }
3096
3097                 track= track->next;
3098         }
3099
3100         if(update) {
3101                 stab->ok= 0;
3102
3103                 DAG_id_tag_update(&clip->id, 0);
3104                 WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, clip);
3105         }
3106
3107         return OPERATOR_FINISHED;
3108 }
3109
3110 void CLIP_OT_stabilize_2d_add(wmOperatorType *ot)
3111 {
3112         /* identifiers */
3113         ot->name= "Add Stabilization Tracks";
3114         ot->description= "Add selected tracks to 2D stabilization tool";
3115         ot->idname= "CLIP_OT_stabilize_2d_add";
3116
3117         /* api callbacks */
3118         ot->exec= stabilize_2d_add_exec;
3119         ot->poll= ED_space_clip_poll;
3120
3121         /* flags */
3122         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
3123 }
3124
3125 /********************** remove 2d stabilization tracks operator *********************/
3126
3127 static int stabilize_2d_remove_exec(bContext *C, wmOperator *UNUSED(op))
3128 {
3129         SpaceClip *sc= CTX_wm_space_clip(C);
3130         MovieClip *clip= ED_space_clip(sc);
3131         MovieTracking *tracking= &clip->tracking;
3132         MovieTrackingStabilization *stab= &tracking->stabilization;
3133         ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
3134         MovieTrackingTrack *track;
3135         int a= 0, update= 0;
3136
3137         track= tracksbase->first;
3138         while(track) {
3139                 if(track->flag&TRACK_USE_2D_STAB) {
3140                         if(a==stab->act_track) {
3141                                 track->flag&= ~TRACK_USE_2D_STAB;
3142
3143                                 stab->act_track--;
3144                                 stab->tot_track--;
3145
3146                                 if(stab->act_track<0)
3147                                         stab->act_track= 0;
3148
3149                                 update= 1;
3150
3151                                 break;
3152                         }
3153
3154                         a++;
3155                 }
3156
3157                 track= track->next;
3158         }
3159
3160         if(update) {
3161                 stab->ok= 0;
3162
3163                 DAG_id_tag_update(&clip->id, 0);
3164                 WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, clip);
3165         }
3166
3167         return OPERATOR_FINISHED;
3168 }
3169
3170 void CLIP_OT_stabilize_2d_remove(wmOperatorType *ot)
3171 {
3172         /* identifiers */
3173         ot->name= "Remove Stabilization Track";
3174         ot->description= "Remove selected track from stabilization";
3175         ot->idname= "CLIP_OT_stabilize_2d_remove";
3176
3177         /* api callbacks */
3178         ot->exec= stabilize_2d_remove_exec;
3179         ot->poll= ED_space_clip_poll;
3180
3181         /* flags */
3182         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
3183 }
3184
3185 /********************** select 2d stabilization tracks operator *********************/
3186
3187 static int stabilize_2d_select_exec(bContext *C, wmOperator *UNUSED(op))
3188 {
3189         SpaceClip *sc= CTX_wm_space_clip(C);
3190         MovieClip *clip= ED_space_clip(sc);
3191         MovieTracking *tracking= &clip->tracking;
3192         ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
3193         MovieTrackingTrack *track;
3194         int update= 0;
3195
3196         track= tracksbase->first;
3197         while(track) {
3198                 if(track->flag&TRACK_USE_2D_STAB) {
3199                         BKE_tracking_track_flag(track, TRACK_AREA_ALL, SELECT, 0);
3200
3201                         update= 1;
3202                 }
3203
3204                 track= track->next;
3205         }
3206
3207         if(update)
3208                 WM_event_add_notifier(C, NC_MOVIECLIP|ND_SELECT, clip);
3209
3210         return OPERATOR_FINISHED;
3211 }
3212
3213 void CLIP_OT_stabilize_2d_select(wmOperatorType *ot)
3214 {
3215         /* identifiers */
3216         ot->name= "Select Stabilization Tracks";
3217         ot->description= "Select track which are used for stabilization";
3218         ot->idname= "CLIP_OT_stabilize_2d_select";
3219
3220         /* api callbacks */
3221         ot->exec= stabilize_2d_select_exec;
3222         ot->poll= ED_space_clip_poll;
3223
3224         /* flags */
3225         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
3226 }
3227
3228 /********************** set 2d stabilization rotation track operator *********************/
3229
3230 static int stabilize_2d_set_rotation_exec(bContext *C, wmOperator *UNUSED(op))
3231 {
3232         SpaceClip *sc= CTX_wm_space_clip(C);
3233         MovieClip *clip= ED_space_clip(sc);
3234         MovieTracking *tracking= &clip->tracking;
3235         MovieTrackingTrack *act_track= BKE_tracking_active_track(tracking);
3236
3237         if(act_track) {
3238                 MovieTrackingStabilization *stab= &tracking->stabilization;
3239
3240                 stab->rot_track= act_track;
3241                 stab->ok= 0;
3242
3243                 DAG_id_tag_update(&clip->id, 0);
3244                 WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, clip);
3245         }
3246
3247         return OPERATOR_FINISHED;
3248 }
3249
3250 void CLIP_OT_stabilize_2d_set_rotation(wmOperatorType *ot)
3251 {
3252         /* identifiers */
3253         ot->name= "Set Rotation Track";
3254         ot->description= "Use active track to compensate rotation when doing 2D stabilization";
3255         ot->idname= "CLIP_OT_stabilize_2d_set_rotation";
3256
3257         /* api callbacks */
3258         ot->exec= stabilize_2d_set_rotation_exec;
3259         ot->poll= ED_space_clip_poll;
3260
3261         /* flags */
3262         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
3263 }
3264
3265 /********************** clean tracks operator *********************/
3266
3267 static int is_track_clean(MovieTrackingTrack *track, int frames, int del)
3268 {
3269         int ok= 1, a, prev= -1, count= 0;
3270         MovieTrackingMarker *markers= track->markers, *new_markers= NULL;
3271         int start_disabled= 0;
3272         int markersnr= track->markersnr;
3273
3274         if(del)