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