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