Fix a particle memory allocation mismatch using MEM_allocN for alloc and BLI_cellallo...
[blender.git] / source / blender / editors / space_clip / tracking_ops.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2011 Blender Foundation.
19  * All rights reserved.
20  *
21  *
22  * Contributor(s): Blender Foundation,
23  *                 Sergey Sharybin
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/space_clip/tracking_ops.c
29  *  \ingroup spclip
30  */
31
32 #include "MEM_guardedalloc.h"
33
34 #include "DNA_camera_types.h"
35 #include "DNA_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(epsy, 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)
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;
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
885         /* do actual selection */
886         track= clip->tracking.tracks.first;
887         while(track) {
888                 if((track->flag&TRACK_HIDDEN)==0) {
889                         MovieTrackingMarker *marker= BKE_tracking_get_marker(track, sc->user.framenr);
890
891                         if(MARKER_VISIBLE(sc, marker) && BLI_in_rctf(&rectf, marker->pos[0], marker->pos[1])) {
892                                 BKE_tracking_track_flag(track, TRACK_AREA_ALL, SELECT, mode!=GESTURE_MODAL_SELECT);
893
894                                 change= 1;
895                         }
896                 }
897
898                 track= track->next;
899         }
900
901         if(change) {
902                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, NULL);
903
904                 return OPERATOR_FINISHED;
905         }
906
907         return OPERATOR_CANCELLED;
908 }
909
910 void CLIP_OT_select_border(wmOperatorType *ot)
911 {
912         /* identifiers */
913         ot->name= "Border Select";
914         ot->description= "Select markers using border selection";
915         ot->idname= "CLIP_OT_select_border";
916
917         /* api callbacks */
918         ot->invoke= WM_border_select_invoke;
919         ot->exec= border_select_exec;
920         ot->modal= WM_border_select_modal;
921         ot->poll= ED_space_clip_poll;
922
923         /* flags */
924         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
925
926         /* properties */
927         WM_operator_properties_gesture_border(ot, FALSE);
928 }
929
930 /********************** circle select operator *********************/
931
932 static int marker_inside_ellipse(MovieTrackingMarker *marker, float offset[2], float ellipse[2])
933 {
934         /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */
935         float x, y;
936
937         x= (marker->pos[0] - offset[0])*ellipse[0];
938         y= (marker->pos[1] - offset[1])*ellipse[1];
939
940         return x*x + y*y < 1.0f;
941 }
942
943 static int circle_select_exec(bContext *C, wmOperator *op)
944 {
945         SpaceClip *sc= CTX_wm_space_clip(C);
946         MovieClip *clip= ED_space_clip(sc);
947         ARegion *ar= CTX_wm_region(C);
948         MovieTrackingTrack *track;
949         int x, y, radius, width, height, mode, change= 0;
950         float zoomx, zoomy, offset[2], ellipse[2];
951
952         /* get operator properties */
953         x= RNA_int_get(op->ptr, "x");
954         y= RNA_int_get(op->ptr, "y");
955         radius= RNA_int_get(op->ptr, "radius");
956
957         mode= RNA_int_get(op->ptr, "gesture_mode");
958
959         /* compute ellipse and position in unified coordinates */
960         ED_space_clip_size(sc, &width, &height);
961         ED_space_clip_zoom(sc, ar, &zoomx, &zoomy);
962
963         ellipse[0]= width*zoomx/radius;
964         ellipse[1]= height*zoomy/radius;
965
966         ED_clip_point_stable_pos(C, x, y, &offset[0], &offset[1]);
967
968         /* do selection */
969         track= clip->tracking.tracks.first;
970         while(track) {
971                 if((track->flag&TRACK_HIDDEN)==0) {
972                         MovieTrackingMarker *marker= BKE_tracking_get_marker(track, sc->user.framenr);
973
974                         if(MARKER_VISIBLE(sc, marker) && marker_inside_ellipse(marker, offset, ellipse)) {
975                                 BKE_tracking_track_flag(track, TRACK_AREA_ALL, SELECT, mode!=GESTURE_MODAL_SELECT);
976
977                                 change= 1;
978                         }
979                 }
980
981                 track= track->next;
982         }
983
984         if(change) {
985                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, NULL);
986
987                 return OPERATOR_FINISHED;
988         }
989
990         return OPERATOR_CANCELLED;
991 }
992
993 void CLIP_OT_select_circle(wmOperatorType *ot)
994 {
995         /* identifiers */
996         ot->name= "Circle Select";
997         ot->description= "Select markers using circle selection";
998         ot->idname= "CLIP_OT_select_circle";
999
1000         /* api callbacks */
1001         ot->invoke= WM_gesture_circle_invoke;
1002         ot->modal= WM_gesture_circle_modal;
1003         ot->exec= circle_select_exec;
1004         ot->poll= ED_space_clip_poll;
1005
1006         /* flags */
1007         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1008
1009         /* properties */
1010         RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
1011         RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
1012         RNA_def_int(ot->srna, "radius", 0, INT_MIN, INT_MAX, "Radius", "", INT_MIN, INT_MAX);
1013         RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Gesture Mode", "", INT_MIN, INT_MAX);
1014 }
1015
1016 /********************** select all operator *********************/
1017
1018 static int select_all_exec(bContext *C, wmOperator *op)
1019 {
1020         SpaceClip *sc= CTX_wm_space_clip(C);
1021         MovieClip *clip= ED_space_clip(sc);
1022         MovieTrackingTrack *track= NULL;        /* selected track */
1023         int action= RNA_enum_get(op->ptr, "action");
1024         int framenr= sc->user.framenr;
1025         int has_selection= 0;
1026
1027         if(action == SEL_TOGGLE){
1028                 action= SEL_SELECT;
1029                 track= clip->tracking.tracks.first;
1030                 while(track) {
1031                         if(TRACK_VIEW_SELECTED(sc, track)) {
1032                                 action= SEL_DESELECT;
1033                                 break;
1034                         }
1035
1036                         track= track->next;
1037                 }
1038         }
1039
1040         track= clip->tracking.tracks.first;
1041         while(track) {
1042                 if((track->flag&TRACK_HIDDEN)==0) {
1043                         MovieTrackingMarker *marker= BKE_tracking_get_marker(track, framenr);
1044
1045                         if(marker && MARKER_VISIBLE(sc, marker)) {
1046                                 switch (action) {
1047                                         case SEL_SELECT:
1048                                                 track->flag|= SELECT;
1049                                                 track->pat_flag|= SELECT;
1050                                                 track->search_flag|= SELECT;
1051                                                 break;
1052                                         case SEL_DESELECT:
1053                                                 track->flag&= ~SELECT;
1054                                                 track->pat_flag&= ~SELECT;
1055                                                 track->search_flag&= ~SELECT;
1056                                                 break;
1057                                         case SEL_INVERT:
1058                                                 track->flag^= SELECT;
1059                                                 track->pat_flag^= SELECT;
1060                                                 track->search_flag^= SELECT;
1061                                                 break;
1062                                 }
1063                         }
1064                 }
1065
1066                 if(TRACK_VIEW_SELECTED(sc, track))
1067                         has_selection= 1;
1068
1069                 track= track->next;
1070         }
1071
1072         if(!has_selection)
1073                 sc->flag&= ~SC_LOCK_SELECTION;
1074
1075         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, NULL);
1076
1077         return OPERATOR_FINISHED;
1078 }
1079
1080 void CLIP_OT_select_all(wmOperatorType *ot)
1081 {
1082         /* identifiers */
1083         ot->name= "Select or Deselect All";
1084         ot->description= "Change selection of all tracking markers";
1085         ot->idname= "CLIP_OT_select_all";
1086
1087         /* api callbacks */
1088         ot->exec= select_all_exec;
1089         ot->poll= ED_space_clip_poll;
1090
1091         /* flags */
1092         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1093
1094         WM_operator_properties_select_all(ot);
1095 }
1096
1097 /********************** select grouped operator *********************/
1098
1099 static int select_groped_exec(bContext *C, wmOperator *op)
1100 {
1101         SpaceClip *sc= CTX_wm_space_clip(C);
1102         MovieClip *clip= ED_space_clip(sc);
1103         MovieTrackingTrack *track;
1104         MovieTrackingMarker *marker;
1105         int group= RNA_enum_get(op->ptr, "group");
1106
1107         track= clip->tracking.tracks.first;
1108         while(track) {
1109                 int ok= 0;
1110
1111                 marker= BKE_tracking_get_marker(track, sc->user.framenr);
1112
1113                 if(group==0) { /* Keyframed */
1114                         ok= marker->framenr==sc->user.framenr && (marker->flag&MARKER_TRACKED)==0;
1115                 }
1116                 else if(group==1) { /* Estimated */
1117                         ok= marker->framenr!=sc->user.framenr;
1118                 }
1119                 else if(group==2) { /* tracked */
1120                         ok= marker->framenr==sc->user.framenr && (marker->flag&MARKER_TRACKED);
1121                 }
1122                 else if(group==3) { /* locked */
1123                         ok= track->flag&TRACK_LOCKED;
1124                 }
1125                 else if(group==4) { /* disabled */
1126                         ok= marker->flag&MARKER_DISABLED;
1127                 }
1128                 else if(group==5) { /* color */
1129                         if(clip->tracking.act_track) {
1130                                 ok= (track->flag&TRACK_CUSTOMCOLOR) == (clip->tracking.act_track->flag&TRACK_CUSTOMCOLOR);
1131
1132                                 if(ok && track->flag&TRACK_CUSTOMCOLOR)
1133                                         ok= equals_v3v3(track->color, clip->tracking.act_track->color);
1134                         }
1135                 }
1136                 else if(group==6) { /* failed */
1137                         ok= (track->flag&TRACK_HAS_BUNDLE) == 0;
1138                 }
1139
1140                 if(ok) {
1141                         track->flag|= SELECT;
1142                         if(sc->flag&SC_SHOW_MARKER_PATTERN) track->pat_flag|= SELECT;;
1143                         if(sc->flag&SC_SHOW_MARKER_SEARCH) track->search_flag|= SELECT;;
1144                 }
1145
1146                 track= track->next;
1147         }
1148
1149         WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, clip);
1150
1151         return OPERATOR_FINISHED;
1152 }
1153
1154 void CLIP_OT_select_grouped(wmOperatorType *ot)
1155 {
1156         static EnumPropertyItem select_group_items[] = {
1157                         {0, "KEYFRAMED", 0, "Keyframed tracks", "Select all keyframed tracks"},
1158                         {1, "ESTIMATED", 0, "Estimated tracks", "Select all estimated tracks"},
1159                         {2, "TRACKED", 0, "Tracked tracks", "Select all tracked tracks"},
1160                         {3, "LOCKED", 0, "Locked tracks", "Select all locked tracks"},
1161                         {4, "DISABLED", 0, "Disabled tracks", "Select all disabled tracks"},
1162                         {5, "COLOR", 0, "Tracks with same color", "Select all tracks with same color as actiev track"},
1163                         {6, "FAILED", 0, "Failed Tracks", "Select all tracks which failed to be reconstructed"},
1164                         {0, NULL, 0, NULL, NULL}
1165         };
1166
1167         /* identifiers */
1168         ot->name= "Select Grouped";
1169         ot->description= "Joint Selected Tracks";
1170         ot->idname= "CLIP_OT_select_grouped";
1171
1172         /* api callbacks */
1173         ot->exec= select_groped_exec;
1174         ot->poll= space_clip_frame_poll;
1175
1176         /* flags */
1177         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1178
1179         /* proeprties */
1180         RNA_def_enum(ot->srna, "group", select_group_items, TRACK_CLEAR_REMAINED, "Action", "Clear action to execute");
1181 }
1182
1183 /********************** track operator *********************/
1184
1185 typedef struct TrackMarkersJob {
1186         struct MovieTrackingContext *context;   /* tracking context */
1187         int sfra, efra, lastfra;        /* Start, end and recently tracked frames */
1188         int backwards;                          /* Backwards tracking flag */
1189         MovieClip *clip;                        /* Clip which is tracking */
1190         float delay;                            /* Delay in milliseconds to allow tracking at fixed FPS */
1191
1192         struct Main *main;
1193         struct Scene *scene;
1194         struct bScreen *screen;
1195 } TrackMarkersJob;
1196
1197 static int track_markers_testbreak(void)
1198 {
1199         return G.afbreek;
1200 }
1201
1202 static int track_count_markers(SpaceClip *sc, MovieClip *clip)
1203 {
1204         int tot= 0;
1205         MovieTrackingTrack *track;
1206
1207         track= clip->tracking.tracks.first;
1208         while(track) {
1209                 if(TRACK_VIEW_SELECTED(sc, track) && (track->flag&TRACK_LOCKED)==0)
1210                         tot++;
1211
1212                 track= track->next;
1213         }
1214
1215         return tot;
1216 }
1217
1218 static void track_init_markers(SpaceClip *sc, MovieClip *clip)
1219 {
1220         MovieTrackingTrack *track;
1221         int framenr= sc->user.framenr, hidden= 0;
1222
1223         if((sc->flag&SC_SHOW_MARKER_PATTERN)==0) hidden|= TRACK_AREA_PAT;
1224         if((sc->flag&SC_SHOW_MARKER_SEARCH)==0) hidden|= TRACK_AREA_SEARCH;
1225
1226         track= clip->tracking.tracks.first;
1227         while(track) {
1228                 if(hidden)
1229                         BKE_tracking_track_flag(track, hidden, SELECT, 1);
1230
1231                 if(TRACK_SELECTED(track)) {
1232                         if((track->flag&TRACK_HIDDEN)==0 && (track->flag&TRACK_LOCKED)==0)
1233                                 BKE_tracking_ensure_marker(track, framenr);
1234                 }
1235
1236                 track= track->next;
1237         }
1238 }
1239
1240 static int track_markers_check_direction(int backwards, int curfra, int efra)
1241 {
1242         if(backwards) {
1243                 if(curfra<efra) return 0;
1244         }
1245         else {
1246                 if(curfra>efra) return 0;
1247         }
1248
1249         return 1;
1250 }
1251
1252 static int track_markers_initjob(bContext *C, TrackMarkersJob *tmj, int backwards)
1253 {
1254         SpaceClip *sc= CTX_wm_space_clip(C);
1255         MovieClip *clip= ED_space_clip(sc);
1256         Scene *scene= CTX_data_scene(C);
1257         MovieTrackingSettings *settings= &clip->tracking.settings;
1258
1259         tmj->sfra= sc->user.framenr;
1260         tmj->clip= clip;
1261         tmj->backwards= backwards;
1262
1263         if(backwards) tmj->efra= SFRA;
1264         else tmj->efra= EFRA;
1265
1266         /* limit frames to be tracked by user setting */
1267         if(settings->frames_limit) {
1268                 if(backwards) tmj->efra= MAX2(tmj->efra, tmj->sfra-settings->frames_limit);
1269                 else tmj->efra= MIN2(tmj->efra, tmj->sfra+settings->frames_limit);
1270         }
1271
1272         if(settings->speed!=TRACKING_SPEED_FASTEST) {
1273                 tmj->delay= 1.0f/scene->r.frs_sec*1000.0f;
1274
1275                 if(settings->speed==TRACKING_SPEED_HALF) tmj->delay*= 2;
1276                 else if(settings->speed==TRACKING_SPEED_QUARTER) tmj->delay*= 4;
1277                 else if(settings->speed==TRACKING_SPEED_DOUBLE) tmj->delay/= 2;
1278         }
1279
1280         track_init_markers(sc, clip);
1281
1282         tmj->context= BKE_tracking_context_new(clip, &sc->user, backwards, 1);
1283
1284         clip->tracking_context= tmj->context;
1285
1286         tmj->lastfra= tmj->sfra;
1287
1288         /* XXX: silly to store this, but this data is needed to update scene and movieclip
1289                 frame numbers when tracking is finished. This introduces better feedback for artists.
1290                 Maybe there's another way to solve this problem, but can't think better way atm.
1291                 Anyway, this way isn't more unstable as animation rendering animation
1292                 which uses the same approach (except storing screen). */
1293         tmj->scene= scene;
1294         tmj->main= CTX_data_main(C);
1295         tmj->screen= CTX_wm_screen(C);
1296
1297         return track_markers_check_direction(backwards, tmj->sfra, tmj->efra);
1298 }
1299
1300 static void track_markers_startjob(void *tmv, short *stop, short *do_update, float *progress)
1301 {
1302         TrackMarkersJob *tmj= (TrackMarkersJob *)tmv;
1303         int framenr= tmj->sfra;
1304         //double t= PIL_check_seconds_timer();
1305
1306         while(framenr != tmj->efra) {
1307                 if(tmj->delay>0) {
1308                         /* tracking should happen with fixed fps. Calculate time
1309                            using current timer value before tracking frame and after.
1310
1311                            Small (and maybe unneeded optimization): do not calculate exec_time
1312                            for "Fastest" tracking */
1313
1314                         double start_time= PIL_check_seconds_timer(), exec_time;
1315
1316                         if(!BKE_tracking_next(tmj->context))
1317                                 break;
1318
1319                         exec_time= PIL_check_seconds_timer()-start_time;
1320                         if(tmj->delay>exec_time)
1321                                 PIL_sleep_ms(tmj->delay-exec_time);
1322                 } else if(!BKE_tracking_next(tmj->context))
1323                                 break;
1324
1325                 *do_update= 1;
1326                 *progress=(float)(framenr-tmj->sfra) / (tmj->efra-tmj->sfra);
1327
1328                 if(tmj->backwards) framenr--;
1329                 else framenr++;
1330
1331                 tmj->lastfra= framenr;
1332
1333                 if(*stop || track_markers_testbreak())
1334                         break;
1335         }
1336
1337         //printf("Tracking time: %lf\n", PIL_check_seconds_timer()-t);
1338 }
1339
1340 static void track_markers_updatejob(void *tmv)
1341 {
1342         TrackMarkersJob *tmj= (TrackMarkersJob *)tmv;
1343
1344         BKE_tracking_sync(tmj->context);
1345 }
1346
1347 static void track_markers_freejob(void *tmv)
1348 {
1349         TrackMarkersJob *tmj= (TrackMarkersJob *)tmv;
1350
1351         tmj->clip->tracking_context= NULL;
1352         tmj->scene->r.cfra= tmj->lastfra;
1353         ED_update_for_newframe(tmj->main, tmj->scene, tmj->screen, 0);
1354
1355         BKE_tracking_sync(tmj->context);
1356         BKE_tracking_context_free(tmj->context);
1357
1358         MEM_freeN(tmj);
1359
1360         WM_main_add_notifier(NC_SCENE|ND_FRAME, tmj->scene);
1361 }
1362
1363 static int track_markers_exec(bContext *C, wmOperator *op)
1364 {
1365         SpaceClip *sc= CTX_wm_space_clip(C);
1366         MovieClip *clip= ED_space_clip(sc);
1367         Scene *scene= CTX_data_scene(C);
1368         struct MovieTrackingContext *context;
1369         int framenr= sc->user.framenr;
1370         int sfra= framenr, efra;
1371         int backwards= RNA_boolean_get(op->ptr, "backwards");
1372         int sequence= RNA_boolean_get(op->ptr, "sequence");
1373         MovieTrackingSettings *settings= &clip->tracking.settings;
1374
1375         if(track_count_markers(sc, clip)==0)
1376                 return OPERATOR_CANCELLED;
1377
1378         if(backwards) efra= SFRA;
1379         else efra= EFRA;
1380
1381         /* limit frames to be tracked by user setting */
1382         if(settings->frames_limit) {
1383                 if(backwards) efra= MAX2(efra, sfra-settings->frames_limit);
1384                 else efra= MIN2(efra, sfra+settings->frames_limit);
1385         }
1386
1387         if(!track_markers_check_direction(backwards, framenr, efra))
1388                 return OPERATOR_CANCELLED;
1389
1390         track_init_markers(sc, clip);
1391
1392         /* do not disable tracks due to threshold when tracking frame-by-frame */
1393         context= BKE_tracking_context_new(clip, &sc->user, backwards, sequence);
1394
1395         while(framenr != efra) {
1396                 if(!BKE_tracking_next(context))
1397                         break;
1398
1399                 if(backwards) framenr--;
1400                 else framenr++;
1401
1402                 if(!sequence)
1403                         break;
1404         }
1405
1406         BKE_tracking_sync(context);
1407         BKE_tracking_context_free(context);
1408
1409         /* update scene current frame to the lastes tracked frame */
1410         scene->r.cfra= framenr;
1411
1412         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
1413         WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
1414
1415         return OPERATOR_FINISHED;
1416 }
1417
1418 static int track_markers_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
1419 {
1420         TrackMarkersJob *tmj;
1421         ScrArea *sa= CTX_wm_area(C);
1422         SpaceClip *sc= CTX_wm_space_clip(C);
1423         MovieClip *clip= ED_space_clip(sc);
1424         wmJob *steve;
1425         int backwards= RNA_boolean_get(op->ptr, "backwards");
1426         int sequence= RNA_boolean_get(op->ptr, "sequence");
1427
1428         if(clip->tracking_context)
1429                 return OPERATOR_CANCELLED;
1430
1431         if(track_count_markers(sc, clip)==0)
1432                 return OPERATOR_CANCELLED;
1433
1434         if(!sequence)
1435                 return track_markers_exec(C, op);
1436
1437         tmj= MEM_callocN(sizeof(TrackMarkersJob), "TrackMarkersJob data");
1438         if(!track_markers_initjob(C, tmj, backwards)) {
1439                 track_markers_freejob(tmj);
1440
1441                 return OPERATOR_CANCELLED;
1442         }
1443
1444         /* setup job */
1445         steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), sa, "Track Markers", WM_JOB_PROGRESS);
1446         WM_jobs_customdata(steve, tmj, track_markers_freejob);
1447
1448         /* if there's delay set in tracking job, tracking should happen
1449            with fixed FPS. To deal with editor refresh we have to syncronize
1450            tracks from job and tracks in clip. Do this in timer callback
1451            to prevent threading conflicts. */
1452         if(tmj->delay>0) WM_jobs_timer(steve, tmj->delay/1000.0f, NC_MOVIECLIP|NA_EVALUATED, 0);
1453         else WM_jobs_timer(steve, 0.2, NC_MOVIECLIP|NA_EVALUATED, 0);
1454
1455         WM_jobs_callbacks(steve, track_markers_startjob, NULL, track_markers_updatejob, NULL);
1456
1457         G.afbreek= 0;
1458
1459         WM_jobs_start(CTX_wm_manager(C), steve);
1460         WM_cursor_wait(0);
1461
1462         /* add modal handler for ESC */
1463         WM_event_add_modal_handler(C, op);
1464
1465         return OPERATOR_RUNNING_MODAL;
1466 }
1467
1468 static int track_markers_modal(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
1469 {
1470         /* no running blender, remove handler and pass through */
1471         if(0==WM_jobs_test(CTX_wm_manager(C), CTX_wm_area(C)))
1472                 return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
1473
1474         /* running tracking */
1475         switch (event->type) {
1476                 case ESCKEY:
1477                         return OPERATOR_RUNNING_MODAL;
1478                         break;
1479         }
1480
1481         return OPERATOR_PASS_THROUGH;
1482 }
1483
1484 void CLIP_OT_track_markers(wmOperatorType *ot)
1485 {
1486         /* identifiers */
1487         ot->name= "Track Markers";
1488         ot->description= "Track selected markers";
1489         ot->idname= "CLIP_OT_track_markers";
1490
1491         /* api callbacks */
1492         ot->exec= track_markers_exec;
1493         ot->invoke= track_markers_invoke;
1494         ot->poll= space_clip_frame_poll;
1495         ot->modal= track_markers_modal;
1496
1497         /* flags */
1498         ot->flag= OPTYPE_UNDO;
1499
1500         /* properties */
1501         RNA_def_boolean(ot->srna, "backwards", 0, "Backwards", "Do backwards tracking");
1502         RNA_def_boolean(ot->srna, "sequence", 0, "Track Sequence", "Track marker during image sequence rather than single image");
1503 }
1504
1505 /********************** solve camera operator *********************/
1506
1507 static int check_solve_track_count(MovieTracking *tracking)
1508 {
1509         int tot= 0;
1510         int frame1= tracking->settings.keyframe1, frame2= tracking->settings.keyframe2;
1511         MovieTrackingTrack *track;
1512
1513         track= tracking->tracks.first;
1514         while(track) {
1515                 if(BKE_tracking_has_marker(track, frame1))
1516                         if(BKE_tracking_has_marker(track, frame2))
1517                                 tot++;
1518
1519                 track= track->next;
1520         }
1521
1522         return tot>=8;
1523 }
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
1534         if(!check_solve_track_count(tracking)) {
1535                 BKE_report(op->reports, RPT_ERROR, "At least 8 tracks on both of keyframes are needed for reconstruction");
1536                 return OPERATOR_CANCELLED;
1537         }
1538
1539         /* could fail if footage uses images with different sizes */
1540         BKE_movieclip_get_size(clip, NULL, &width, &height);
1541
1542         error= BKE_tracking_solve_reconstruction(tracking, width, height);
1543
1544         if(error<0)
1545                 BKE_report(op->reports, RPT_WARNING, "Some data failed to reconstruct, see console for details");
1546         else
1547                 BKE_reportf(op->reports, RPT_INFO, "Average reprojection error %.3f", error);
1548
1549         scene->clip= clip;
1550         id_us_plus(&clip->id);
1551
1552         if(!scene->camera)
1553                 scene->camera= scene_find_camera(scene);
1554
1555         if(scene->camera) {
1556                 /* set blender camera focal length so result would look fine there */
1557                 Camera *camera= (Camera*)scene->camera->data;
1558
1559                 BKE_tracking_camera_to_blender(tracking, scene, camera, width, height);
1560
1561                 WM_event_add_notifier(C, NC_OBJECT, camera);
1562         }
1563
1564         DAG_id_tag_update(&clip->id, 0);
1565
1566         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
1567         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
1568
1569         /* update active clip displayed in scene buttons */
1570         WM_event_add_notifier(C, NC_SCENE, scene);
1571
1572         return OPERATOR_FINISHED;
1573 }
1574
1575 void CLIP_OT_solve_camera(wmOperatorType *ot)
1576 {
1577         /* identifiers */
1578         ot->name= "Solve Camera";
1579         ot->description= "Solve camera motion from tracks";
1580         ot->idname= "CLIP_OT_solve_camera";
1581
1582         /* api callbacks */
1583         ot->exec= solve_camera_exec;
1584         ot->poll= ED_space_clip_poll;
1585
1586         /* flags */
1587         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1588 }
1589
1590 /********************** clear solution operator *********************/
1591
1592 static int clear_solution_exec(bContext *C, wmOperator *UNUSED(op))
1593 {
1594         SpaceClip *sc= CTX_wm_space_clip(C);
1595         MovieClip *clip= ED_space_clip(sc);
1596         MovieTracking *tracking= &clip->tracking;
1597         MovieTrackingTrack *track= tracking->tracks.first;
1598
1599         while(track) {
1600                 track->flag&= ~TRACK_HAS_BUNDLE;
1601
1602                 track= track->next;
1603         }
1604
1605         if(tracking->reconstruction.cameras)
1606                 MEM_freeN(tracking->reconstruction.cameras);
1607
1608         tracking->reconstruction.cameras= NULL;
1609         tracking->reconstruction.camnr= 0;
1610
1611         tracking->reconstruction.flag&= ~TRACKING_RECONSTRUCTED;
1612
1613         DAG_id_tag_update(&clip->id, 0);
1614
1615         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
1616         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, NULL);
1617
1618         return OPERATOR_FINISHED;
1619 }
1620
1621 void CLIP_OT_clear_solution(wmOperatorType *ot)
1622 {
1623         /* identifiers */
1624         ot->name= "Clear Solution";
1625         ot->description= "Clear all calculated data";
1626         ot->idname= "CLIP_OT_clear_solution";
1627
1628         /* api callbacks */
1629         ot->exec= clear_solution_exec;
1630         ot->poll= ED_space_clip_poll;
1631
1632         /* flags */
1633         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1634 }
1635
1636 /********************** clear track operator *********************/
1637
1638 static int clear_track_path_exec(bContext *C, wmOperator *op)
1639 {
1640         SpaceClip *sc= CTX_wm_space_clip(C);
1641         MovieClip *clip= ED_space_clip(sc);
1642         MovieTrackingTrack *track;
1643         int action= RNA_enum_get(op->ptr, "action");
1644
1645         track= clip->tracking.tracks.first;
1646         while(track) {
1647                 if(TRACK_VIEW_SELECTED(sc, track))
1648                         BKE_tracking_clear_path(track, sc->user.framenr, action);
1649
1650                 track= track->next;
1651         }
1652
1653         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
1654
1655         return OPERATOR_FINISHED;
1656 }
1657
1658 void CLIP_OT_clear_track_path(wmOperatorType *ot)
1659 {
1660         static EnumPropertyItem clear_path_actions[] = {
1661                         {TRACK_CLEAR_UPTO, "UPTO", 0, "Clear up-to", "Clear path up to current frame"},
1662                         {TRACK_CLEAR_REMAINED, "REMAINED", 0, "Clear remained", "Clear path at remained frames (after current)"},
1663                         {TRACK_CLEAR_ALL, "ALL", 0, "Clear all", "Clear the whole path"},
1664                         {0, NULL, 0, NULL, NULL}
1665         };
1666
1667         /* identifiers */
1668         ot->name= "Clear Track Path";
1669         ot->description= "Clear path of selected tracks";
1670         ot->idname= "CLIP_OT_clear_track_path";
1671
1672         /* api callbacks */
1673         ot->exec= clear_track_path_exec;
1674         ot->poll= ED_space_clip_poll;
1675
1676         /* flags */
1677         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1678
1679         /* proeprties */
1680         RNA_def_enum(ot->srna, "action", clear_path_actions, TRACK_CLEAR_REMAINED, "Action", "Clear action to execute");
1681 }
1682
1683 /********************** disable markers operator *********************/
1684
1685 static int disable_markers_exec(bContext *C, wmOperator *op)
1686 {
1687         SpaceClip *sc= CTX_wm_space_clip(C);
1688         MovieClip *clip= ED_space_clip(sc);
1689         MovieTracking *tracking= &clip->tracking;
1690         MovieTrackingTrack *track= tracking->tracks.first;
1691         int action= RNA_enum_get(op->ptr, "action");
1692
1693         while(track) {
1694                 if(TRACK_VIEW_SELECTED(sc, track) && (track->flag&TRACK_LOCKED)==0) {
1695                         MovieTrackingMarker *marker= BKE_tracking_ensure_marker(track, sc->user.framenr);
1696
1697                         if(action==0) marker->flag|= MARKER_DISABLED;
1698                         else if(action==1) marker->flag&= ~MARKER_DISABLED;
1699                         else marker->flag^= MARKER_DISABLED;
1700                 }
1701
1702                 track= track->next;
1703         }
1704
1705         DAG_id_tag_update(&clip->id, 0);
1706
1707         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
1708
1709         return OPERATOR_FINISHED;
1710 }
1711
1712 void CLIP_OT_disable_markers(wmOperatorType *ot)
1713 {
1714         static EnumPropertyItem actions_items[] = {
1715                         {0, "DISABLE", 0, "Disable", "Disable selected markers"},
1716                         {1, "ENABLE", 0, "Enable", "Enable selected markers"},
1717                         {2, "TOGGLE", 0, "Toggle", "Toggle disabled flag for selected markers"},
1718                         {0, NULL, 0, NULL, NULL}
1719         };
1720
1721         /* identifiers */
1722         ot->name= "Disable Markers";
1723         ot->description= "Disable/enable selected markers";
1724         ot->idname= "CLIP_OT_disable_markers";
1725
1726         /* api callbacks */
1727         ot->exec= disable_markers_exec;
1728         ot->poll= ED_space_clip_poll;
1729
1730         /* flags */
1731         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1732
1733         /* properties */
1734         RNA_def_enum(ot->srna, "action", actions_items, 0, "Action", "Disable action to execute");
1735 }
1736
1737 /********************** set origin operator *********************/
1738
1739 static int count_selected_bundles(bContext *C)
1740 {
1741         SpaceClip *sc= CTX_wm_space_clip(C);
1742         MovieClip *clip= ED_space_clip(sc);
1743         MovieTrackingTrack *track;
1744         int tot= 0;
1745
1746         track= clip->tracking.tracks.first;
1747         while(track) {
1748                 if(TRACK_VIEW_SELECTED(sc, track) && (track->flag&TRACK_HAS_BUNDLE))
1749                         tot++;
1750
1751                 track= track->next;
1752         }
1753
1754         return tot;
1755 }
1756
1757 static int set_origin_exec(bContext *C, wmOperator *op)
1758 {
1759         SpaceClip *sc= CTX_wm_space_clip(C);
1760         MovieClip *clip= ED_space_clip(sc);
1761         MovieTrackingTrack *track;
1762         Scene *scene= CTX_data_scene(C);
1763         Object *parent= scene->camera;
1764         float mat[4][4], vec[3];
1765
1766         if(count_selected_bundles(C)!=1) {
1767                 BKE_report(op->reports, RPT_ERROR, "Track with bundle should be selected to define origin position");
1768                 return OPERATOR_CANCELLED;
1769         }
1770
1771         if(scene->camera->parent)
1772                 parent= scene->camera->parent;
1773
1774         track= clip->tracking.tracks.first;
1775         while(track) {
1776                 if(TRACK_VIEW_SELECTED(sc, track))
1777                         break;
1778
1779                 track= track->next;
1780         }
1781
1782         BKE_get_tracking_mat(scene, NULL, mat);
1783         mul_v3_m4v3(vec, mat, track->bundle_pos);
1784
1785         sub_v3_v3(parent->loc, vec);
1786
1787         DAG_id_tag_update(&clip->id, 0);
1788         DAG_id_tag_update(&parent->id, OB_RECALC_OB);
1789
1790         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
1791         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
1792
1793         return OPERATOR_FINISHED;
1794 }
1795
1796 void CLIP_OT_set_origin(wmOperatorType *ot)
1797 {
1798         /* identifiers */
1799         ot->name= "Set Origin";
1800         ot->description= "Set active marker as origin by moving camera (or it's parent if present) in 3d space";
1801         ot->idname= "CLIP_OT_set_origin";
1802
1803         /* api callbacks */
1804         ot->exec= set_origin_exec;
1805         ot->poll= space_clip_frame_camera_poll;
1806
1807         /* flags */
1808         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1809 }
1810
1811 /********************** set floor operator *********************/
1812
1813 static void set_axis(Scene *scene,  Object *ob, MovieTrackingTrack *track, char axis)
1814 {
1815         float mat[4][4], vec[3], obmat[4][4];
1816
1817         BKE_get_tracking_mat(scene, NULL, mat);
1818         mul_v3_m4v3(vec, mat, track->bundle_pos);
1819
1820         if(len_v2(vec)<1e-3)
1821                 return;
1822
1823         unit_m4(mat);
1824
1825         if(axis=='X') {
1826                 if(fabsf(vec[1])<1e-3) {
1827                         mat[0][0]= -1.0f; mat[0][1]= 0.0f; mat[0][2]= 0.0f;
1828                         mat[1][0]= 0.0f; mat[1][1]= -1.0f; mat[1][2]= 0.0f;
1829                         mat[2][0]= 0.0f; mat[2][1]= 0.0f; mat[2][2]= 1.0f;
1830                 } else {
1831                         copy_v3_v3(mat[0], vec);
1832                         mat[0][2]= 0.0f;
1833                         mat[2][0]= 0.0f; mat[2][1]= 0.0f; mat[2][2]= 1.0f;
1834                         cross_v3_v3v3(mat[1], mat[2], mat[0]);
1835                 }
1836         } else {
1837                 if(fabsf(vec[0])<1e-3) {
1838                         mat[0][0]= -1.0f; mat[0][1]= 0.0f; mat[0][2]= 0.0f;
1839                         mat[1][0]= 0.0f; mat[1][1]= -1.0f; mat[1][2]= 0.0f;
1840                         mat[2][0]= 0.0f; mat[2][1]= 0.0f; mat[2][2]= 1.0f;
1841                 } else {
1842                         copy_v3_v3(mat[1], vec);
1843                         mat[1][2]= 0.0f;
1844                         mat[2][0]= 0.0f; mat[2][1]= 0.0f; mat[2][2]= 1.0f;
1845                         cross_v3_v3v3(mat[0], mat[1], mat[2]);
1846                 }
1847         }
1848
1849         normalize_v3(mat[0]);
1850         normalize_v3(mat[1]);
1851         normalize_v3(mat[2]);
1852
1853         invert_m4(mat);
1854
1855         object_to_mat4(ob, obmat);
1856         mul_m4_m4m4(mat, obmat, mat);
1857         object_apply_mat4(ob, mat, 0, 0);
1858 }
1859
1860 static int set_floor_exec(bContext *C, wmOperator *op)
1861 {
1862         SpaceClip *sc= CTX_wm_space_clip(C);
1863         MovieClip *clip= ED_space_clip(sc);
1864         Scene *scene= CTX_data_scene(C);
1865         MovieTrackingTrack *track, *axis_track= NULL;
1866         Object *camera= scene->camera;
1867         Object *parent= camera;
1868         int tot= 0;
1869         float vec[3][3], mat[4][4], obmat[4][4], newmat[4][4], orig[3]= {0.0f, 0.0f, 0.0f};
1870         float rot[4][4]={{0.0f, 0.0f, -1.0f, 0.0f},
1871                          {0.0f, 1.0f, 0.0f, 0.0f},
1872                          {1.0f, 0.0f, 0.0f, 0.0f},
1873                          {0.0f, 0.0f, 0.0f, 1.0f}};     /* 90 degrees Y-axis rotation matrix */
1874
1875         if(count_selected_bundles(C)!=3) {
1876                 BKE_report(op->reports, RPT_ERROR, "Three tracks with bundles are needed to orient the floor");
1877                 return OPERATOR_CANCELLED;
1878         }
1879
1880         if(scene->camera->parent)
1881                 parent= scene->camera->parent;
1882
1883         BKE_get_tracking_mat(scene, NULL, mat);
1884
1885         /* get 3 bundles to use as reference */
1886         track= clip->tracking.tracks.first;
1887         while(track && tot<3) {
1888                 if(track->flag&TRACK_HAS_BUNDLE && TRACK_VIEW_SELECTED(sc, track)) {
1889                         mul_v3_m4v3(vec[tot], mat, track->bundle_pos);
1890
1891                         if(tot==0 || track==clip->tracking.act_track)
1892                                 copy_v3_v3(orig, vec[tot]);
1893                         else
1894                                 axis_track= track;
1895
1896                         tot++;
1897                 }
1898
1899                 track= track->next;
1900         }
1901
1902         sub_v3_v3(vec[1], vec[0]);
1903         sub_v3_v3(vec[2], vec[0]);
1904
1905         /* construct ortho-normal basis */
1906         unit_m4(mat);
1907
1908         cross_v3_v3v3(mat[0], vec[1], vec[2]);
1909         copy_v3_v3(mat[1], vec[1]);
1910         cross_v3_v3v3(mat[2], mat[0], mat[1]);
1911
1912         normalize_v3(mat[0]);
1913         normalize_v3(mat[1]);
1914         normalize_v3(mat[2]);
1915
1916         /* move to origin point */
1917         mat[3][0]= orig[0];
1918         mat[3][1]= orig[1];
1919         mat[3][2]= orig[2];
1920
1921         invert_m4(mat);
1922
1923         object_to_mat4(parent, obmat);
1924         mul_m4_m4m4(mat, obmat, mat);
1925         mul_m4_m4m4(newmat, mat, rot);
1926         object_apply_mat4(parent, newmat, 0, 0);
1927
1928         /* make camera have positive z-coordinate */
1929         mul_v3_m4v3(vec[0], mat, camera->loc);
1930         if(camera->loc[2]<0) {
1931                 invert_m4(rot);
1932                 mul_m4_m4m4(newmat, mat, rot);
1933                 object_apply_mat4(camera, newmat, 0, 0);
1934         }
1935
1936         where_is_object(scene, parent);
1937         set_axis(scene, parent, axis_track, 'X');
1938
1939         DAG_id_tag_update(&clip->id, 0);
1940         DAG_id_tag_update(&parent->id, OB_RECALC_OB);
1941
1942         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
1943         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
1944
1945         return OPERATOR_FINISHED;
1946 }
1947
1948 void CLIP_OT_set_floor(wmOperatorType *ot)
1949 {
1950         /* identifiers */
1951         ot->name= "Set Floor";
1952         ot->description= "Set floor based on 3 selected bundles by moving camera (or it's parent if present) in 3d space";
1953         ot->idname= "CLIP_OT_set_floor";
1954
1955         /* api callbacks */
1956         ot->exec= set_floor_exec;
1957         ot->poll= space_clip_camera_poll;
1958
1959         /* flags */
1960         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1961 }
1962
1963 /********************** set axis operator *********************/
1964
1965 static int set_axis_exec(bContext *C, wmOperator *op)
1966 {
1967         SpaceClip *sc= CTX_wm_space_clip(C);
1968         MovieClip *clip= ED_space_clip(sc);
1969         MovieTrackingTrack *track;
1970         Scene *scene= CTX_data_scene(C);
1971         Object *parent= scene->camera;
1972         int axis= RNA_enum_get(op->ptr, "axis");
1973
1974         if(count_selected_bundles(C)!=1) {
1975                 BKE_report(op->reports, RPT_ERROR, "Single track with bundle should be selected to define axis");
1976
1977                 return OPERATOR_CANCELLED;
1978         }
1979
1980         if(scene->camera->parent)
1981                 parent= scene->camera->parent;
1982
1983         track= clip->tracking.tracks.first;
1984         while(track) {
1985                 if(TRACK_VIEW_SELECTED(sc, track))
1986                         break;
1987
1988                 track= track->next;
1989         }
1990
1991         set_axis(scene, parent, track, axis==0?'X':'Y');
1992
1993         DAG_id_tag_update(&clip->id, 0);
1994         DAG_id_tag_update(&parent->id, OB_RECALC_OB);
1995
1996         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
1997         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
1998
1999         return OPERATOR_FINISHED;
2000 }
2001
2002 void CLIP_OT_set_axis(wmOperatorType *ot)
2003 {
2004         static EnumPropertyItem axis_actions[] = {
2005                         {0, "X", 0, "X", "Align bundle align X axis"},
2006                         {1, "Y", 0, "Y", "Align bundle align Y axis"},
2007                         {0, NULL, 0, NULL, NULL}
2008         };
2009
2010         /* identifiers */
2011         ot->name= "Set Axis";
2012         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";
2013         ot->idname= "CLIP_OT_set_axis";
2014
2015         /* api callbacks */
2016         ot->exec= set_axis_exec;
2017         ot->poll= space_clip_frame_camera_poll;
2018
2019         /* flags */
2020         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2021
2022         /* properties */
2023         RNA_def_enum(ot->srna, "axis", axis_actions, 0, "Axis", "Axis to use to align bundle along");
2024 }
2025
2026 /********************** set scale operator *********************/
2027
2028 static int set_scale_exec(bContext *C, wmOperator *op)
2029 {
2030         SpaceClip *sc= CTX_wm_space_clip(C);
2031         MovieClip *clip= ED_space_clip(sc);
2032         MovieTrackingTrack *track;
2033         Scene *scene= CTX_data_scene(C);
2034         Object *parent= scene->camera;
2035         int tot= 0;
2036         float vec[2][3], mat[4][4], scale;
2037         float dist= RNA_float_get(op->ptr, "distance");
2038
2039         if(count_selected_bundles(C)!=2) {
2040                 BKE_report(op->reports, RPT_ERROR, "Two tracks with bundles should be selected to scale scene");
2041
2042                 return OPERATOR_CANCELLED;
2043         }
2044
2045         if(scene->camera->parent)
2046                 parent= scene->camera->parent;
2047
2048         BKE_get_tracking_mat(scene, NULL, mat);
2049
2050         track= clip->tracking.tracks.first;
2051         while(track) {
2052                 if(TRACK_VIEW_SELECTED(sc, track)) {
2053                         mul_v3_m4v3(vec[tot], mat, track->bundle_pos);
2054                         tot++;
2055                 }
2056
2057                 track= track->next;
2058         }
2059
2060         sub_v3_v3(vec[0], vec[1]);
2061
2062         if(len_v3(vec[0])>1e-5) {
2063                 scale= dist / len_v3(vec[0]);
2064
2065                 mul_v3_fl(parent->size, scale);
2066                 mul_v3_fl(parent->loc, scale);
2067
2068                 DAG_id_tag_update(&clip->id, 0);
2069                 DAG_id_tag_update(&parent->id, OB_RECALC_OB);
2070
2071                 WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
2072                 WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
2073         }
2074
2075         return OPERATOR_FINISHED;
2076 }
2077
2078 static int set_scale_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
2079 {
2080         SpaceClip *sc= CTX_wm_space_clip(C);
2081         MovieClip *clip= ED_space_clip(sc);
2082         float dist= RNA_float_get(op->ptr, "distance");
2083
2084         if(dist==0.0f)
2085                 RNA_float_set(op->ptr, "distance", clip->tracking.settings.dist);
2086
2087         return set_scale_exec(C, op);
2088 }
2089
2090 void CLIP_OT_set_scale(wmOperatorType *ot)
2091 {
2092         /* identifiers */
2093         ot->name= "Set Scale";
2094         ot->description= "Set scale of scene by scaling camera (or it's parent if present)";
2095         ot->idname= "CLIP_OT_set_scale";
2096
2097         /* api callbacks */
2098         ot->exec= set_scale_exec;
2099         ot->invoke= set_scale_invoke;
2100         ot->poll= space_clip_frame_camera_poll;
2101
2102         /* flags */
2103         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2104
2105         /* properties */
2106         RNA_def_float(ot->srna, "distance", 0.0f, -FLT_MAX, FLT_MAX,
2107                 "Distance", "Distance between selected tracks", -100.0f, 100.0f);
2108 }
2109
2110 /********************** set principal center operator *********************/
2111
2112 static int set_center_principal_exec(bContext *C, wmOperator *UNUSED(op))
2113 {
2114         SpaceClip *sc= CTX_wm_space_clip(C);
2115         MovieClip *clip= ED_space_clip(sc);
2116         int width, height;
2117
2118         BKE_movieclip_get_size(clip, &sc->user, &width, &height);
2119
2120         if(width==0 || height==0)
2121                 return OPERATOR_CANCELLED;
2122
2123         clip->tracking.camera.principal[0]= ((float)width)/2.0f;
2124         clip->tracking.camera.principal[1]= ((float)height)/2.0f;
2125
2126         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, clip);
2127
2128         return OPERATOR_FINISHED;
2129 }
2130
2131 void CLIP_OT_set_center_principal(wmOperatorType *ot)
2132 {
2133         /* identifiers */
2134         ot->name= "Set Principal to Center";
2135         ot->description= "Set principal point to center of footage";
2136         ot->idname= "CLIP_OT_set_center_principal";
2137
2138         /* api callbacks */
2139         ot->exec= set_center_principal_exec;
2140         ot->poll= ED_space_clip_poll;
2141
2142         /* flags */
2143         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2144 }
2145
2146 /********************** hide tracks operator *********************/
2147
2148 static int hide_tracks_exec(bContext *C, wmOperator *op)
2149 {
2150         SpaceClip *sc= CTX_wm_space_clip(C);
2151         MovieClip *clip= ED_space_clip(sc);
2152         MovieTrackingTrack *track;
2153         int unselected;
2154
2155         unselected= RNA_boolean_get(op->ptr, "unselected");
2156
2157         track= clip->tracking.tracks.first;
2158         while(track) {
2159                 if(unselected==0 && TRACK_VIEW_SELECTED(sc, track)) {
2160                         track->flag|= TRACK_HIDDEN;
2161                 } else if(unselected==1 && !TRACK_VIEW_SELECTED(sc, track)) {
2162                         track->flag|= TRACK_HIDDEN;
2163                 }
2164
2165                 track= track->next;
2166         }
2167
2168         if(clip->tracking.act_track && clip->tracking.act_track->flag&TRACK_HIDDEN)
2169                 clip->tracking.act_track= NULL;
2170
2171         if(unselected==0) {
2172                 /* no selection on screen now, unlock view so it can be scrolled nice again */
2173                 sc->flag&= ~SC_LOCK_SELECTION;
2174         }
2175
2176         WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, NULL);
2177
2178         return OPERATOR_FINISHED;
2179 }
2180
2181 void CLIP_OT_hide_tracks(wmOperatorType *ot)
2182 {
2183         /* identifiers */
2184         ot->name= "Hide Tracks";
2185         ot->description= "Hide selected tracks";
2186         ot->idname= "CLIP_OT_hide_tracks";
2187
2188         /* api callbacks */
2189         ot->exec= hide_tracks_exec;
2190         ot->poll= ED_space_clip_poll;
2191
2192         /* flags */
2193         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2194
2195         /* properties */
2196         RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected tracks");
2197 }
2198
2199 /********************** hide tracks clear operator *********************/
2200
2201 static int hide_tracks_clear_exec(bContext *C, wmOperator *UNUSED(op))
2202 {
2203         SpaceClip *sc= CTX_wm_space_clip(C);
2204         MovieClip *clip= ED_space_clip(sc);
2205         MovieTrackingTrack *track;
2206
2207         track= clip->tracking.tracks.first;
2208         while(track) {
2209                 track->flag&= ~TRACK_HIDDEN;
2210
2211                 track= track->next;
2212         }
2213
2214         WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, NULL);
2215
2216         return OPERATOR_FINISHED;
2217 }
2218
2219 void CLIP_OT_hide_tracks_clear(wmOperatorType *ot)
2220 {
2221         /* identifiers */
2222         ot->name= "Hide Tracks Clear";
2223         ot->description= "Clear hide selected tracks";
2224         ot->idname= "CLIP_OT_hide_tracks_clear";
2225
2226         /* api callbacks */
2227         ot->exec= hide_tracks_clear_exec;
2228         ot->poll= ED_space_clip_poll;
2229
2230         /* flags */
2231         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2232 }
2233
2234 /********************** detect features operator *********************/
2235
2236 static bGPDlayer *detect_get_layer(MovieClip *clip)
2237 {
2238         bGPDlayer *layer;
2239
2240         if(!clip->gpd)
2241                 return NULL;
2242
2243         layer= clip->gpd->layers.first;
2244         while(layer) {
2245                 if(layer->flag&GP_LAYER_ACTIVE)
2246                         return layer;
2247
2248                 layer= layer->next;
2249         }
2250
2251         return NULL;
2252 }
2253
2254 static int detect_features_exec(bContext *C, wmOperator *op)
2255 {
2256         SpaceClip *sc= CTX_wm_space_clip(C);
2257         MovieClip *clip= ED_space_clip(sc);
2258         ImBuf *ibuf= BKE_movieclip_get_ibuf_flag(clip, &sc->user, 0);
2259         MovieTrackingTrack *track= clip->tracking.tracks.first;
2260         int placement= RNA_enum_get(op->ptr, "placement");
2261         int margin= RNA_int_get(op->ptr, "margin");
2262         int min_trackness= RNA_int_get(op->ptr, "min_trackness");
2263         int min_distance= RNA_int_get(op->ptr, "min_distance");
2264         int place_outside_layer= 0;
2265         bGPDlayer *layer= NULL;
2266
2267         if(placement!=0) {
2268                 layer= detect_get_layer(clip);
2269                 place_outside_layer= placement==2;
2270         }
2271
2272         /* deselect existing tracks */
2273         while(track) {
2274                 track->flag&= ~SELECT;
2275                 track->pat_flag&= ~SELECT;
2276                 track->search_flag&= ~SELECT;
2277
2278                 track= track->next;
2279         }
2280
2281         BKE_tracking_detect_fast(&clip->tracking, ibuf, sc->user.framenr, margin, min_trackness, min_distance, layer, place_outside_layer);
2282
2283         IMB_freeImBuf(ibuf);
2284
2285         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, NULL);
2286
2287         return OPERATOR_FINISHED;
2288 }
2289
2290 void CLIP_OT_detect_features(wmOperatorType *ot)
2291 {
2292         static EnumPropertyItem placement_items[] = {
2293                         {0, "FRAME",                    0, "Whole Frame",                       "Place markers across the whole frame"},
2294                         {1, "INSIDE_GPENCIL",   0, "Inside grease pencil",      "Place markers only inside areas oulined with grease pencil"},
2295                         {2, "OUTSIDE_GPENCIL",  0, "Outside grease pencil",     "Place markers only outside areas oulined with grease pencil"},
2296                         {0, NULL, 0, NULL, NULL}
2297         };
2298
2299         /* identifiers */
2300         ot->name= "Detect Features";
2301         ot->description= "Automatically detect features to track";
2302         ot->idname= "CLIP_OT_detect_features";
2303
2304         /* api callbacks */
2305         ot->exec= detect_features_exec;
2306         ot->poll= space_clip_frame_poll;
2307
2308         /* flags */
2309         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2310
2311         /* properties */
2312         RNA_def_enum(ot->srna, "placement", placement_items, 0, "Placement", "Placement for detected features");
2313         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);
2314         RNA_def_int(ot->srna, "min_trackness", 16, 0, INT_MAX, "Trackness", "Minimum score to add a corner", 0, 300);
2315         RNA_def_int(ot->srna, "min_distance", 120, 0, INT_MAX, "Distance", "Minimal distance accepted between two corners", 0, 300);
2316 }
2317
2318 /********************** frame jump operator *********************/
2319
2320 static int frame_jump_exec(bContext *C, wmOperator *op)
2321 {
2322         Scene *scene= CTX_data_scene(C);
2323         SpaceClip *sc= CTX_wm_space_clip(C);
2324         MovieClip *clip= ED_space_clip(sc);
2325         MovieTrackingTrack *track;
2326         int pos= RNA_enum_get(op->ptr, "position");
2327         int delta;
2328
2329         if(pos<=1) {    /* jump to path */
2330                 track= clip->tracking.act_track;
2331
2332                 if(!track)
2333                         return OPERATOR_CANCELLED;
2334
2335                 delta= pos == 1 ? 1 : -1;
2336
2337                 while(sc->user.framenr+delta >= SFRA && sc->user.framenr+delta <= EFRA) {
2338                         MovieTrackingMarker *marker= BKE_tracking_exact_marker(track, sc->user.framenr+delta);
2339
2340                         if(!marker || marker->flag&MARKER_DISABLED)
2341                                 break;
2342
2343                         sc->user.framenr+= delta;
2344                 }
2345         }
2346         else {  /* to to failed frame */
2347                 if(clip->tracking.reconstruction.flag&TRACKING_RECONSTRUCTED) {
2348                         int a= sc->user.framenr;
2349                         MovieTracking *tracking= &clip->tracking;
2350
2351                         delta= pos == 3 ? 1 : -1;
2352
2353                         a+= delta;
2354
2355                         while(a+delta >= SFRA && a+delta <= EFRA) {
2356                                 MovieReconstructedCamera *cam= BKE_tracking_get_reconstructed_camera(tracking, a);
2357
2358                                 if(!cam) {
2359                                         sc->user.framenr= a;
2360
2361                                         break;
2362                                 }
2363
2364                                 a+= delta;
2365                         }
2366                 }
2367         }
2368
2369         if(CFRA!=sc->user.framenr) {
2370                 CFRA= sc->user.framenr;
2371                 sound_seek_scene(CTX_data_main(C), CTX_data_scene(C));
2372
2373                 WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
2374         }
2375
2376         WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, NULL);
2377
2378         return OPERATOR_FINISHED;
2379 }
2380
2381 void CLIP_OT_frame_jump(wmOperatorType *ot)
2382 {
2383         static EnumPropertyItem position_items[] = {
2384                         {0, "PATHSTART",        0, "Path Start",                "Jump to start of current path"},
2385                         {1, "PATHEND",          0, "Path End",                  "Jump to end of current path"},
2386                         {2, "FAILEDPREV",       0, "Previons Failed",   "Jump to previous failed frame"},
2387                         {2, "FAILNEXT",         0, "Next Failed",               "Jump to next failed frame"},
2388                         {0, NULL, 0, NULL, NULL}
2389         };
2390
2391         /* identifiers */
2392         ot->name= "Jump to Frame";
2393         ot->description= "Jump to special frame";
2394         ot->idname= "CLIP_OT_frame_jump";
2395
2396         /* api callbacks */
2397         ot->exec= frame_jump_exec;
2398         ot->poll= space_clip_frame_poll;
2399
2400         /* flags */
2401         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2402
2403         /* properties */
2404         RNA_def_enum(ot->srna, "position", position_items, 0, "Position", "Position to jumo to");
2405 }
2406
2407 /********************** join tracks operator *********************/
2408
2409 static int join_tracks_exec(bContext *C, wmOperator *op)
2410 {
2411         SpaceClip *sc= CTX_wm_space_clip(C);
2412         MovieClip *clip= ED_space_clip(sc);
2413         MovieTrackingTrack *act_track, *track, *next;
2414
2415         act_track= clip->tracking.act_track;
2416
2417         if(!act_track) {
2418                 BKE_report(op->reports, RPT_ERROR, "No active track to join to");
2419                 return OPERATOR_CANCELLED;
2420         }
2421
2422         track= clip->tracking.tracks.first;
2423         while(track) {
2424                 if(TRACK_VIEW_SELECTED(sc, track) && track!=act_track) {
2425                         if(!BKE_tracking_test_join_tracks(act_track, track)) {
2426                                 BKE_report(op->reports, RPT_ERROR, "Some selected tracks have got keyframed markers to the same frame");
2427                                 return OPERATOR_CANCELLED;
2428                         }
2429                 }
2430
2431                 track= track->next;
2432         }
2433
2434         track= clip->tracking.tracks.first;
2435         while(track) {
2436                 next= track->next;
2437
2438                 if(TRACK_VIEW_SELECTED(sc, track) && track!=act_track) {
2439                         BKE_tracking_join_tracks(act_track, track);
2440
2441                         BKE_tracking_free_track(track);
2442                         BLI_freelinkN(&clip->tracking.tracks, track);
2443                 }
2444
2445                 track= next;
2446         }
2447
2448         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, clip);
2449
2450         return OPERATOR_FINISHED;
2451 }
2452
2453 void CLIP_OT_join_tracks(wmOperatorType *ot)
2454 {
2455         /* identifiers */
2456         ot->name= "Join Tracks";
2457         ot->description= "Joint Selected Tracks";
2458         ot->idname= "CLIP_OT_join_tracks";
2459
2460         /* api callbacks */
2461         ot->exec= join_tracks_exec;
2462         ot->poll= space_clip_frame_poll;
2463
2464         /* flags */
2465         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2466 }
2467
2468 /********************** lock tracks operator *********************/
2469
2470 static int lock_tracks_exec(bContext *C, wmOperator *op)
2471 {
2472         SpaceClip *sc= CTX_wm_space_clip(C);
2473         MovieClip *clip= ED_space_clip(sc);
2474         MovieTracking *tracking= &clip->tracking;
2475         MovieTrackingTrack *track= tracking->tracks.first;
2476         int action= RNA_enum_get(op->ptr, "action");
2477
2478         while(track) {
2479                 if(TRACK_VIEW_SELECTED(sc, track)) {
2480                         if(action==0) track->flag|= TRACK_LOCKED;
2481                         else if(action==1) track->flag&= ~TRACK_LOCKED;
2482                         else track->flag^= TRACK_LOCKED;
2483                 }
2484
2485                 track= track->next;
2486         }
2487
2488         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
2489
2490         return OPERATOR_FINISHED;
2491 }
2492
2493 void CLIP_OT_lock_tracks(wmOperatorType *ot)
2494 {
2495         static EnumPropertyItem actions_items[] = {
2496                         {0, "LOCK", 0, "Lock", "Lock selected tracks"},
2497                         {1, "UNLOCK", 0, "Unlock", "Unlock selected tracks"},
2498                         {2, "TOGGLE", 0, "Toggle", "Toggle locked flag for selected tracks"},
2499                         {0, NULL, 0, NULL, NULL}
2500         };
2501
2502         /* identifiers */
2503         ot->name= "Lock Tracks";
2504         ot->description= "Lock/unlock selected tracks";
2505         ot->idname= "CLIP_OT_lock_tracks";
2506
2507         /* api callbacks */
2508         ot->exec= lock_tracks_exec;
2509         ot->poll= ED_space_clip_poll;
2510
2511         /* flags */
2512         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2513
2514         /* properties */
2515         RNA_def_enum(ot->srna, "action", actions_items, 0, "Action", "Lock action to execute");
2516 }
2517
2518 /********************** track copy color operator *********************/
2519
2520 static int track_copy_color_exec(bContext *C, wmOperator *UNUSED(op))
2521 {
2522         SpaceClip *sc= CTX_wm_space_clip(C);
2523         MovieClip *clip= ED_space_clip(sc);
2524         MovieTrackingTrack *track, *act_track= clip->tracking.act_track;
2525
2526         if(!act_track)
2527                 return OPERATOR_CANCELLED;
2528
2529         track= clip->tracking.tracks.first;
2530         while(track) {
2531                 if(TRACK_VIEW_SELECTED(sc, track) && track!=act_track) {
2532                         track->flag&= ~TRACK_CUSTOMCOLOR;
2533
2534                         if(act_track->flag&TRACK_CUSTOMCOLOR) {
2535                                 copy_v3_v3(track->color, act_track->color);
2536                                 track->flag|= TRACK_CUSTOMCOLOR;
2537                         }
2538                 }
2539
2540                 track= track->next;
2541         }
2542
2543         WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, clip);
2544
2545         return OPERATOR_FINISHED;
2546 }
2547
2548 void CLIP_OT_track_copy_color(wmOperatorType *ot)
2549 {
2550         /* identifiers */
2551         ot->name= "Copy Color";
2552         ot->description= "Copy color to all selected tracks";
2553         ot->idname= "CLIP_OT_track_copy_color";
2554
2555         /* api callbacks */
2556         ot->exec= track_copy_color_exec;
2557         ot->poll= ED_space_clip_poll;
2558
2559         /* flags */
2560         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2561 }
2562
2563 /********************** add 2d stabilization tracks operator *********************/
2564
2565 static int stabilize_2d_add_exec(bContext *C, wmOperator *UNUSED(op))
2566 {
2567         SpaceClip *sc= CTX_wm_space_clip(C);
2568         MovieClip *clip= ED_space_clip(sc);
2569         MovieTracking *tracking= &clip->tracking;
2570         MovieTrackingTrack *track;
2571         MovieTrackingStabilization *stab= &tracking->stabilization;
2572         int update= 0;
2573
2574         track= tracking->tracks.first;
2575         while(track) {
2576                 if(TRACK_VIEW_SELECTED(sc, track) && (track->flag&TRACK_USE_2D_STAB)==0) {
2577                         track->flag|= TRACK_USE_2D_STAB;
2578                         stab->tot_track++;
2579
2580                         update= 1;
2581                 }
2582
2583                 track= track->next;
2584         }
2585
2586         if(update) {
2587                 stab->ok= 0;
2588
2589                 DAG_id_tag_update(&clip->id, 0);
2590                 WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, clip);
2591         }
2592
2593         return OPERATOR_FINISHED;
2594 }
2595
2596 void CLIP_OT_stabilize_2d_add(wmOperatorType *ot)
2597 {
2598         /* identifiers */
2599         ot->name= "Add Stabilization Tracks";
2600         ot->description= "Add selected tracks to 2D stabilization tool";
2601         ot->idname= "CLIP_OT_stabilize_2d_add";
2602
2603         /* api callbacks */
2604         ot->exec= stabilize_2d_add_exec;
2605         ot->poll= ED_space_clip_poll;
2606
2607         /* flags */
2608         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2609 }
2610
2611 /********************** remove 2d stabilization tracks operator *********************/
2612
2613 static int stabilize_2d_remove_exec(bContext *C, wmOperator *UNUSED(op))
2614 {
2615         SpaceClip *sc= CTX_wm_space_clip(C);
2616         MovieClip *clip= ED_space_clip(sc);
2617         MovieTracking *tracking= &clip->tracking;
2618         MovieTrackingStabilization *stab= &tracking->stabilization;
2619         MovieTrackingTrack *track;
2620         int a= 0, update= 0;
2621
2622         track= tracking->tracks.first;
2623         while(track) {
2624                 if(track->flag&TRACK_USE_2D_STAB) {
2625                         if(a==stab->act_track) {
2626                                 track->flag&= ~TRACK_USE_2D_STAB;
2627
2628                                 stab->act_track--;
2629                                 stab->tot_track--;
2630
2631                                 if(stab->act_track<0)
2632                                         stab->act_track= 0;
2633
2634                                 update= 1;
2635
2636                                 break;
2637                         }
2638
2639                         a++;
2640                 }
2641
2642                 track= track->next;
2643         }
2644
2645         if(update) {
2646                 stab->ok= 0;
2647
2648                 DAG_id_tag_update(&clip->id, 0);
2649                 WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, clip);
2650         }
2651
2652         return OPERATOR_FINISHED;
2653 }
2654
2655 void CLIP_OT_stabilize_2d_remove(wmOperatorType *ot)
2656 {
2657         /* identifiers */
2658         ot->name= "Remove Stabilization Track";
2659         ot->description= "Remove selected track from stabilization";
2660         ot->idname= "CLIP_OT_stabilize_2d_remove";
2661
2662         /* api callbacks */
2663         ot->exec= stabilize_2d_remove_exec;
2664         ot->poll= ED_space_clip_poll;
2665
2666         /* flags */
2667         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2668 }
2669
2670 /********************** select 2d stabilization tracks operator *********************/
2671
2672 static int stabilize_2d_select_exec(bContext *C, wmOperator *UNUSED(op))
2673 {
2674         SpaceClip *sc= CTX_wm_space_clip(C);
2675         MovieClip *clip= ED_space_clip(sc);
2676         MovieTracking *tracking= &clip->tracking;
2677         MovieTrackingTrack *track;
2678         int update= 0;
2679
2680         track= tracking->tracks.first;
2681         while(track) {
2682                 if(track->flag&TRACK_USE_2D_STAB) {
2683                         BKE_tracking_track_flag(track, TRACK_AREA_ALL, SELECT, 0);
2684
2685                         update= 1;
2686                 }
2687
2688                 track= track->next;
2689         }
2690
2691         if(update)
2692                 WM_event_add_notifier(C, NC_MOVIECLIP|ND_SELECT, clip);
2693
2694         return OPERATOR_FINISHED;
2695 }
2696
2697 void CLIP_OT_stabilize_2d_select(wmOperatorType *ot)
2698 {
2699         /* identifiers */
2700         ot->name= "Select Stabilization Tracks";
2701         ot->description= "Select track which are used for stabilization";
2702         ot->idname= "CLIP_OT_stabilize_2d_select";
2703
2704         /* api callbacks */
2705         ot->exec= stabilize_2d_select_exec;
2706         ot->poll= ED_space_clip_poll;
2707
2708         /* flags */
2709         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2710 }
2711
2712 /********************** set 2d stabilization rotation track operator *********************/
2713
2714 static int stabilize_2d_set_rotation_exec(bContext *C, wmOperator *UNUSED(op))
2715 {
2716         SpaceClip *sc= CTX_wm_space_clip(C);
2717         MovieClip *clip= ED_space_clip(sc);
2718         MovieTracking *tracking= &clip->tracking;
2719
2720         if(tracking->act_track) {
2721                 MovieTrackingStabilization *stab= &tracking->stabilization;
2722
2723                 stab->rot_track= tracking->act_track;
2724                 stab->ok= 0;
2725
2726                 DAG_id_tag_update(&clip->id, 0);
2727                 WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, clip);
2728         }
2729
2730         return OPERATOR_FINISHED;
2731 }
2732
2733 void CLIP_OT_stabilize_2d_set_rotation(wmOperatorType *ot)
2734 {
2735         /* identifiers */
2736         ot->name= "Set Rotation Track";
2737         ot->description= "Use active track to compensate rotaiton when doing 2D stabilization";
2738         ot->idname= "CLIP_OT_stabilize_2d_set_rotation";
2739
2740         /* api callbacks */
2741         ot->exec= stabilize_2d_set_rotation_exec;
2742         ot->poll= ED_space_clip_poll;
2743
2744         /* flags */
2745         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2746 }
2747
2748 /********************** clean tracks operator *********************/
2749
2750 static int is_track_clean(MovieTrackingTrack *track, int frames, int del)
2751 {
2752         int ok= 1, a, prev= -1, count= 0;
2753         MovieTrackingMarker *markers= track->markers, *new_markers= NULL;
2754         int start_disabled= 0;
2755         int markersnr= track->markersnr;
2756
2757         if(del)
2758                 new_markers= MEM_callocN(markersnr*sizeof(MovieTrackingMarker), "track cleaned markers");
2759
2760         for(a= 0; a<markersnr; a++) {
2761                 int end= 0;
2762
2763                 if(prev==-1) {
2764                         if((markers[a].flag&MARKER_DISABLED)==0)
2765                                 prev= a;
2766                         else
2767                                 start_disabled= 1;
2768                 }
2769
2770                 if(prev >= 0) {
2771                         end=  a == markersnr-1;
2772                         end|= (a < markersnr-1) && (markers[a].framenr != markers[a+1].framenr-1 ||
2773                                                     markers[a].flag&MARKER_DISABLED);
2774                 }
2775
2776                 if(end) {
2777                         int segok= 1, len= 0;
2778
2779                         if(a != prev && markers[a].framenr != markers[a-1].framenr+1)
2780                                 len= a-prev;
2781                         else if(markers[a].flag&MARKER_DISABLED)
2782                                 len= a-prev;
2783                         else len= a-prev+1;
2784
2785                         if(frames) {
2786                                 if(len < frames) {
2787                                         segok= 0;
2788                                         ok= 0;
2789
2790                                         if(!del)
2791                                                 break;
2792                                 }
2793                         }
2794
2795                         if(del) {
2796                                 if(segok) {
2797                                         int t= len;
2798
2799                                         if(markers[a].flag&MARKER_DISABLED)
2800                                                 t++;
2801
2802                                         /* place disabled marker in front of current segment */
2803                                         if(start_disabled) {
2804                                                 memcpy(new_markers+count, markers+prev, sizeof(MovieTrackingMarker));
2805                                                 new_markers[count].framenr--;
2806                                                 new_markers[count].flag|= MARKER_DISABLED;
2807
2808                                                 count++;
2809                                                 start_disabled= 0;
2810                                         }
2811
2812                                         memcpy(new_markers+count, markers+prev, t*sizeof(MovieTrackingMarker));
2813                                         count+= t;
2814                                 }
2815                                 else if(markers[a].flag&MARKER_DISABLED) {
2816                                         /* current segment which would be deleted was finished by disabled marker,
2817                                            so next segment should be started from disabled marker */
2818                                         start_disabled= 1;
2819                                 }
2820                         }
2821
2822                         prev= -1;
2823                 }
2824         }
2825
2826         if(del) {
2827                 MEM_freeN(track->markers);
2828
2829                 if(count) {
2830                         track->markers= new_markers;
2831                 }
2832                 else {
2833                         track->markers= NULL;
2834                         MEM_freeN(new_markers);
2835                 }
2836
2837                 track->markersnr= count;
2838         }
2839
2840         return ok;
2841 }
2842
2843 static int clean_tracks_exec(bContext *C, wmOperator *op)
2844 {
2845         SpaceClip *sc= CTX_wm_space_clip(C);
2846         MovieClip *clip= ED_space_clip(sc);
2847         MovieTracking *tracking= &clip->tracking;
2848         MovieTrackingTrack *track, *next, *act_track= clip->tracking.act_track;
2849         int frames= RNA_int_get(op->ptr, "frames");
2850         int action= RNA_enum_get(op->ptr, "action");
2851         float error= RNA_float_get(op->ptr, "error");
2852
2853         if(error && action==TRACKING_CLEAN_DELETE_SEGMENT)
2854                 action= TRACKING_CLEAN_DELETE_TRACK;
2855
2856         track= tracking->tracks.first;
2857         while(track) {
2858                 next= track->next;
2859
2860                 if((track->flag&TRACK_HIDDEN)==0 && (track->flag&TRACK_LOCKED)==0) {
2861                         int ok= 1;
2862
2863                         ok= (is_track_clean(track, frames, action==TRACKING_CLEAN_DELETE_SEGMENT)) &&
2864                             (error == 0.0f || (track->flag&TRACK_HAS_BUNDLE)==0  || track->error < error);
2865
2866                         if(!ok) {
2867                                 if(action==TRACKING_CLEAN_SELECT) {
2868                                         BKE_tracking_track_flag(track, TRACK_AREA_ALL, SELECT, 0);
2869                                 }
2870                                 else if(action==TRACKING_CLEAN_DELETE_TRACK) {
2871                                         if(track==act_track)
2872                                                 clip->tracking.act_track= NULL;
2873
2874                                         BKE_tracking_free_track(track);
2875                                         BLI_freelinkN(&clip->tracking.tracks, track);
2876                                         track= NULL;
2877                                 }
2878
2879                                 /* happens when all tracking segments are not long enough */
2880                                 if(track && track->markersnr==0) {
2881                                         if(track==act_track)
2882                                                 clip->tracking.act_track= NULL;
2883
2884                                         BKE_tracking_free_track(track);
2885                                         BLI_freelinkN(&clip->tracking.tracks, track);
2886                                 }
2887                         }
2888                 }
2889
2890                 track= next;
2891         }
2892
2893         WM_event_add_notifier(C, NC_MOVIECLIP|ND_SELECT, clip);
2894
2895         return OPERATOR_FINISHED;
2896 }
2897
2898 static int clean_tracks_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
2899 {
2900         SpaceClip *sc= CTX_wm_space_clip(C);
2901         MovieClip *clip= ED_space_clip(sc);
2902         int frames= RNA_int_get(op->ptr, "frames");
2903         float error= RNA_float_get(op->ptr, "error");
2904         int action= RNA_enum_get(op->ptr, "action");
2905
2906         if(frames==0 && error==0 && action==0) {
2907                 RNA_int_set(op->ptr, "frames", clip->tracking.settings.clean_frames);
2908                 RNA_float_set(op->ptr, "error", clip->tracking.settings.clean_error);
2909                 RNA_enum_set(op->ptr, "action", clip->tracking.settings.clean_action);
2910         }
2911
2912         return clean_tracks_exec(C, op);
2913 }
2914
2915 void CLIP_OT_clean_tracks(wmOperatorType *ot)
2916 {
2917         static EnumPropertyItem actions_items[] = {
2918                         {TRACKING_CLEAN_SELECT, "SELECT", 0, "Select", "Select unclean tracks"},
2919                         {TRACKING_CLEAN_DELETE_TRACK, "DELETE_TRACK", 0, "Delete Track", "Delete unclean tracks"},
2920                         {TRACKING_CLEAN_DELETE_SEGMENT, "DELETE_SEGMENTS", 0, "Delete Segments", "Delete unclean segments of tracks"},
2921                         {0, NULL, 0, NULL, NULL}
2922         };
2923
2924         /* identifiers */
2925         ot->name= "Clean Tracks";
2926         ot->description= "Clean tracks";
2927         ot->idname= "CLIP_OT_clean_tracks";
2928
2929         /* api callbacks */
2930         ot->exec= clean_tracks_exec;
2931         ot->invoke= clean_tracks_invoke;
2932         ot->poll= ED_space_clip_poll;
2933
2934         /* flags */
2935         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2936
2937         /* properties */
2938         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);
2939         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);
2940         RNA_def_enum(ot->srna, "action", actions_items, 0, "Action", "Cleanup action to execute");
2941 }