Camera tracking integration
[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         float error;
1490
1491         if(!check_solve_tarck_count(&clip->tracking)) {
1492                 BKE_report(op->reports, RPT_ERROR, "At least 10 tracks on both of keyframes are needed for reconstruction");
1493                 return OPERATOR_CANCELLED;
1494         }
1495
1496         error = BKE_tracking_solve_reconstruction(clip);
1497
1498         if(error<0)
1499                 BKE_report(op->reports, RPT_WARNING, "Some data failed to reconstruct, see console for details");
1500         else
1501                 BKE_reportf(op->reports, RPT_INFO, "Average reprojection error %.3f", error);
1502
1503         scene->clip= clip;
1504
1505         if(!scene->camera)
1506                 scene->camera= scene_find_camera(scene);
1507
1508         if(scene->camera) {
1509                 MovieTracking *tracking= &clip->tracking;
1510                 float focal= tracking->camera.focal;
1511
1512                 /* set blender camera focal length so result would look fine there */
1513                 if(focal) {
1514                         Camera *camera= (Camera*)scene->camera->data;
1515
1516                         if(clip->lastsize[0]) {
1517                                 camera->sensor_x= tracking->camera.sensor_width;
1518                                 camera->sensor_y= tracking->camera.sensor_height;
1519
1520                                 camera->lens= focal*camera->sensor_x/(float)clip->lastsize[0];
1521                         }
1522
1523                         WM_event_add_notifier(C, NC_OBJECT, camera);
1524                 }
1525         }
1526
1527         DAG_id_tag_update(&clip->id, 0);
1528
1529         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
1530         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, NULL);
1531
1532         return OPERATOR_FINISHED;
1533 }
1534
1535 void CLIP_OT_solve_camera(wmOperatorType *ot)
1536 {
1537         /* identifiers */
1538         ot->name= "Solve Camera";
1539         ot->description= "Solve camera motion from tracks";
1540         ot->idname= "CLIP_OT_solve_camera";
1541
1542         /* api callbacks */
1543         ot->exec= solve_camera_exec;
1544         ot->poll= space_clip_tracking_poll;
1545
1546         /* flags */
1547         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1548 }
1549
1550 /********************** clear reconstruction operator *********************/
1551
1552 static int clear_reconstruction_exec(bContext *C, wmOperator *UNUSED(op))
1553 {
1554         SpaceClip *sc= CTX_wm_space_clip(C);
1555         MovieClip *clip= ED_space_clip(sc);
1556         MovieTracking *tracking= &clip->tracking;
1557         MovieTrackingTrack *track= tracking->tracks.first;
1558
1559         while(track) {
1560                 track->flag&= ~TRACK_HAS_BUNDLE;
1561
1562                 track= track->next;
1563         }
1564
1565         if(tracking->camera.reconstructed)
1566                 MEM_freeN(tracking->camera.reconstructed);
1567
1568         tracking->camera.reconstructed= NULL;
1569         tracking->camera.reconnr= 0;
1570
1571         DAG_id_tag_update(&clip->id, 0);
1572
1573         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
1574         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, NULL);
1575
1576         return OPERATOR_FINISHED;
1577 }
1578
1579 void CLIP_OT_clear_reconstruction(wmOperatorType *ot)
1580 {
1581         /* identifiers */
1582         ot->name= "Clear Reconstruciton";
1583         ot->description= "Clear all reconstruciton data";
1584         ot->idname= "CLIP_OT_clear_reconstruction";
1585
1586         /* api callbacks */
1587         ot->exec= clear_reconstruction_exec;
1588         ot->poll= space_clip_tracking_poll;
1589
1590         /* flags */
1591         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1592 }
1593
1594 /********************** clear track operator *********************/
1595
1596 static int clear_track_path_exec(bContext *C, wmOperator *op)
1597 {
1598         SpaceClip *sc= CTX_wm_space_clip(C);
1599         MovieClip *clip= ED_space_clip(sc);
1600         MovieTrackingTrack *track;
1601         int action= RNA_enum_get(op->ptr, "action");
1602
1603         track= clip->tracking.tracks.first;
1604         while(track) {
1605                 if(TRACK_SELECTED(track))
1606                         BKE_tracking_clear_path(track, sc->user.framenr, action);
1607
1608                 track= track->next;
1609         }
1610
1611         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
1612
1613         return OPERATOR_FINISHED;
1614 }
1615
1616 void CLIP_OT_clear_track_path(wmOperatorType *ot)
1617 {
1618         static EnumPropertyItem clear_path_actions[] = {
1619                         {TRACK_CLEAR_UPTO, "UPTO", 0, "Clear up-to", "Clear path up to current frame"},
1620                         {TRACK_CLEAR_REMAINED, "REMAINED", 0, "Clear remained", "Clear path at remained frames (after current)"},
1621                         {TRACK_CLEAR_ALL, "ALL", 0, "Clear all", "Clear the whole path"},
1622                         {0, NULL, 0, NULL, NULL}
1623         };
1624
1625         /* identifiers */
1626         ot->name= "Clear Track Path";
1627         ot->description= "Clear path of selected tracks";
1628         ot->idname= "CLIP_OT_clear_track_path";
1629
1630         /* api callbacks */
1631         ot->exec= clear_track_path_exec;
1632         ot->poll= space_clip_tracking_poll;
1633
1634         /* flags */
1635         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1636
1637         /* proeprties */
1638         RNA_def_enum(ot->srna, "action", clear_path_actions, TRACK_CLEAR_REMAINED, "Action", "Clear action to execute");
1639 }
1640
1641 /********************** disable markers operator *********************/
1642
1643 static int disable_markers_exec(bContext *C, wmOperator *op)
1644 {
1645         SpaceClip *sc= CTX_wm_space_clip(C);
1646         MovieClip *clip= ED_space_clip(sc);
1647         MovieTracking *tracking= &clip->tracking;
1648         MovieTrackingTrack *track= tracking->tracks.first;
1649         int action= RNA_enum_get(op->ptr, "action");
1650
1651         while(track) {
1652                 if(TRACK_SELECTED(track) && (track->flag&TRACK_LOCKED)==0) {
1653                         MovieTrackingMarker *marker= BKE_tracking_ensure_marker(track, sc->user.framenr);
1654
1655                         if(action==0) marker->flag|= MARKER_DISABLED;
1656                         else if(action==1) marker->flag&= ~MARKER_DISABLED;
1657                         else marker->flag^= MARKER_DISABLED;
1658                 }
1659
1660                 track= track->next;
1661         }
1662
1663         DAG_id_tag_update(&clip->id, 0);
1664
1665         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
1666
1667         return OPERATOR_FINISHED;
1668 }
1669
1670 void CLIP_OT_disable_markers(wmOperatorType *ot)
1671 {
1672         static EnumPropertyItem actions_items[] = {
1673                         {0, "DISABLE", 0, "Disable", "Disable selected markers"},
1674                         {1, "ENABLE", 0, "Enable", "Enable selected markers"},
1675                         {2, "TOGGLE", 0, "Toggle", "Toggle disabled flag for selected markers"},
1676                         {0, NULL, 0, NULL, NULL}
1677         };
1678
1679         /* identifiers */
1680         ot->name= "Disable Markers";
1681         ot->description= "Disable/enable selected markers";
1682         ot->idname= "CLIP_OT_disable_markers";
1683
1684         /* api callbacks */
1685         ot->exec= disable_markers_exec;
1686         ot->poll= space_clip_tracking_poll;
1687
1688         /* flags */
1689         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1690
1691         /* properties */
1692         RNA_def_enum(ot->srna, "action", actions_items, 0, "Action", "Disable action to execute");
1693 }
1694
1695 /********************** set origin operator *********************/
1696
1697 static int count_selected_bundles(bContext *C)
1698 {
1699         SpaceClip *sc= CTX_wm_space_clip(C);
1700         MovieClip *clip= ED_space_clip(sc);
1701         MovieTrackingTrack *track;
1702         int tot= 0;
1703
1704         track= clip->tracking.tracks.first;
1705         while(track) {
1706                 if(TRACK_SELECTED(track))
1707                         tot++;
1708
1709                 track= track->next;
1710         }
1711
1712         return tot;
1713 }
1714
1715 static int set_origin_exec(bContext *C, wmOperator *op)
1716 {
1717         SpaceClip *sc= CTX_wm_space_clip(C);
1718         MovieClip *clip= ED_space_clip(sc);
1719         MovieTrackingTrack *track;
1720         Scene *scene= CTX_data_scene(C);
1721         Object *parent= scene->camera;
1722         float mat[4][4], vec[3];
1723
1724         if(count_selected_bundles(C)!=1) {
1725                 BKE_report(op->reports, RPT_ERROR, "Track with bundle should be selected to define origin position");
1726                 return OPERATOR_CANCELLED;
1727         }
1728
1729         if(scene->camera->parent)
1730                 parent= scene->camera->parent;
1731
1732         track= clip->tracking.tracks.first;
1733         while(track) {
1734                 if(TRACK_SELECTED(track))
1735                         break;
1736
1737                 track= track->next;
1738         }
1739
1740         BKE_get_tracking_mat(scene, mat);
1741         mul_v3_m4v3(vec, mat, track->bundle_pos);
1742
1743         sub_v3_v3(parent->loc, vec);
1744
1745         DAG_id_tag_update(&clip->id, 0);
1746         DAG_id_tag_update(&parent->id, OB_RECALC_OB);
1747
1748         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
1749         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, NULL);
1750
1751         return OPERATOR_FINISHED;
1752 }
1753
1754 void CLIP_OT_set_origin(wmOperatorType *ot)
1755 {
1756         /* identifiers */
1757         ot->name= "Set Origin";
1758         ot->description= "Set active marker as origin";
1759         ot->idname= "CLIP_OT_set_origin";
1760
1761         /* api callbacks */
1762         ot->exec= set_origin_exec;
1763         ot->poll= space_clip_frame_camera_poll;
1764
1765         /* flags */
1766         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1767 }
1768
1769 /********************** set floor operator *********************/
1770
1771 static void set_axis(Scene *scene,  Object *ob, MovieTrackingTrack *track, char axis)
1772 {
1773         float mat[4][4], vec[3], obmat[4][4];
1774
1775         BKE_get_tracking_mat(scene, mat);
1776         mul_v3_m4v3(vec, mat, track->bundle_pos);
1777
1778         if(len_v2(vec)<1e-3)
1779                 return;
1780
1781         unit_m4(mat);
1782
1783         if(axis=='X') {
1784                 if(fabsf(vec[1])<1e-3) {
1785                         mat[0][0]= -1.f; mat[0][1]= 0.f; mat[0][2]= 0.f;
1786                         mat[1][0]= 0.f; mat[1][1]= -1.f; mat[1][2]= 0.f;
1787                         mat[2][0]= 0.f; mat[2][1]= 0.f; mat[2][2]= 1.0f;
1788                 } else {
1789                         copy_v3_v3(mat[0], vec);
1790                         mat[0][2]= 0.f;
1791                         mat[2][0]= 0.f; mat[2][1]= 0.f; mat[2][2]= 1.0f;
1792                         cross_v3_v3v3(mat[1], mat[2], mat[0]);
1793                 }
1794         } else {
1795                 if(fabsf(vec[0])<1e-3) {
1796                         mat[0][0]= -1.f; mat[0][1]= 0.f; mat[0][2]= 0.f;
1797                         mat[1][0]= 0.f; mat[1][1]= -1.f; mat[1][2]= 0.f;
1798                         mat[2][0]= 0.f; mat[2][1]= 0.f; mat[2][2]= 1.0f;
1799                 } else {
1800                         copy_v3_v3(mat[1], vec);
1801                         mat[1][2]= 0.f;
1802                         mat[2][0]= 0.f; mat[2][1]= 0.f; mat[2][2]= 1.0f;
1803                         cross_v3_v3v3(mat[0], mat[1], mat[2]);
1804                 }
1805         }
1806
1807         normalize_v3(mat[0]);
1808         normalize_v3(mat[1]);
1809         normalize_v3(mat[2]);
1810
1811         invert_m4(mat);
1812
1813         object_to_mat4(ob, obmat);
1814         mul_m4_m4m4(mat, obmat, mat);
1815         object_apply_mat4(ob, mat, 0, 0);
1816 }
1817
1818 static int set_floor_exec(bContext *C, wmOperator *op)
1819 {
1820         SpaceClip *sc= CTX_wm_space_clip(C);
1821         MovieClip *clip= ED_space_clip(sc);
1822         Scene *scene= CTX_data_scene(C);
1823         MovieTrackingTrack *track, *sel, *axis_track= NULL;
1824         Object *camera= scene->camera;
1825         Object *parent= camera;
1826         int tot= 0, sel_type;
1827         float vec[3][3], mat[4][4], obmat[4][4], newmat[4][4], orig[3]= {0.f, 0.f, 0.f};
1828         float rot[4][4]={{0.f, 0.f, -1.f, 0.f},
1829                          {0.f, 1.f, 0.f, 0.f},
1830                          {1.f, 0.f, 0.f, 0.f},
1831                          {0.f, 0.f, 0.f, 1.f}}; /* 90 degrees Y-axis rotation matrix */
1832
1833         if(count_selected_bundles(C)!=3) {
1834                 BKE_report(op->reports, RPT_ERROR, "Three tracks with bundles are needed to orient the floor");
1835                 return OPERATOR_CANCELLED;
1836         }
1837
1838         if(scene->camera->parent)
1839                 parent= scene->camera->parent;
1840
1841         BKE_get_tracking_mat(scene, mat);
1842
1843         BKE_movieclip_last_selection(clip, &sel_type, (void**)&sel);
1844
1845         /* get 3 bundles to use as reference */
1846         track= clip->tracking.tracks.first;
1847         while(track && tot<3) {
1848                 if(track->flag&TRACK_HAS_BUNDLE && TRACK_SELECTED(track)) {
1849                         mul_v3_m4v3(vec[tot], mat, track->bundle_pos);
1850
1851                         if(tot==0 || (sel_type==MCLIP_SEL_TRACK && track==sel))
1852                                 copy_v3_v3(orig, vec[tot]);
1853                         else
1854                                 axis_track= track;
1855
1856                         tot++;
1857                 }
1858
1859                 track= track->next;
1860         }
1861
1862         sub_v3_v3(vec[1], vec[0]);
1863         sub_v3_v3(vec[2], vec[0]);
1864
1865         /* construct ortho-normal basis */
1866         unit_m4(mat);
1867
1868         cross_v3_v3v3(mat[0], vec[1], vec[2]);
1869         copy_v3_v3(mat[1], vec[1]);
1870         cross_v3_v3v3(mat[2], mat[0], mat[1]);
1871
1872         normalize_v3(mat[0]);
1873         normalize_v3(mat[1]);
1874         normalize_v3(mat[2]);
1875
1876         /* move to origin point */
1877         mat[3][0]= orig[0];
1878         mat[3][1]= orig[1];
1879         mat[3][2]= orig[2];
1880
1881         invert_m4(mat);
1882
1883         object_to_mat4(parent, obmat);
1884         mul_m4_m4m4(mat, obmat, mat);
1885         mul_m4_m4m4(newmat, mat, rot);
1886         object_apply_mat4(parent, newmat, 0, 0);
1887
1888         /* make camera have positive z-coordinate */
1889         mul_v3_m4v3(vec[0], mat, camera->loc);
1890         if(camera->loc[2]<0) {
1891                 invert_m4(rot);
1892                 mul_m4_m4m4(newmat, mat, rot);
1893                 object_apply_mat4(camera, newmat, 0, 0);
1894         }
1895
1896         where_is_object(scene, parent);
1897         set_axis(scene, parent, axis_track, 'X');
1898
1899         DAG_id_tag_update(&clip->id, 0);
1900         DAG_id_tag_update(&parent->id, OB_RECALC_OB);
1901
1902         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
1903         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, NULL);
1904
1905         return OPERATOR_FINISHED;
1906 }
1907
1908 void CLIP_OT_set_floor(wmOperatorType *ot)
1909 {
1910         /* identifiers */
1911         ot->name= "Set Floor";
1912         ot->description= "Set floor using 3 selected bundles";
1913         ot->idname= "CLIP_OT_set_floor";
1914
1915         /* api callbacks */
1916         ot->exec= set_floor_exec;
1917         ot->poll= space_clip_camera_poll;
1918
1919         /* flags */
1920         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1921 }
1922
1923 /********************** set origin operator *********************/
1924
1925 static int set_axis_exec(bContext *C, wmOperator *op)
1926 {
1927         SpaceClip *sc= CTX_wm_space_clip(C);
1928         MovieClip *clip= ED_space_clip(sc);
1929         MovieTrackingTrack *track;
1930         Scene *scene= CTX_data_scene(C);
1931         Object *parent= scene->camera;
1932         int axis= RNA_enum_get(op->ptr, "axis");
1933
1934         if(count_selected_bundles(C)!=1) {
1935                 BKE_report(op->reports, RPT_ERROR, "Track with bundle should be selected to define X-axis");
1936
1937                 return OPERATOR_CANCELLED;
1938         }
1939
1940         if(scene->camera->parent)
1941                 parent= scene->camera->parent;
1942
1943         track= clip->tracking.tracks.first;
1944         while(track) {
1945                 if(TRACK_SELECTED(track))
1946                         break;
1947
1948                 track= track->next;
1949         }
1950
1951         set_axis(scene, parent, track, axis==0?'X':'Y');
1952
1953         DAG_id_tag_update(&clip->id, 0);
1954         DAG_id_tag_update(&parent->id, OB_RECALC_OB);
1955
1956         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
1957         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, NULL);
1958
1959         return OPERATOR_FINISHED;
1960 }
1961
1962 void CLIP_OT_set_axis(wmOperatorType *ot)
1963 {
1964         static EnumPropertyItem axis_actions[] = {
1965                         {0, "X", 0, "X", "Align bundle align X axis"},
1966                         {1, "Y", 0, "Y", "Align bundle align Y axis"},
1967                         {0, NULL, 0, NULL, NULL}
1968         };
1969
1970         /* identifiers */
1971         ot->name= "Set Axis";
1972         ot->description= "Set direction of scene axis";
1973         ot->idname= "CLIP_OT_set_axis";
1974
1975         /* api callbacks */
1976         ot->exec= set_axis_exec;
1977         ot->poll= space_clip_frame_camera_poll;
1978
1979         /* flags */
1980         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1981
1982         /* properties */
1983         RNA_def_enum(ot->srna, "axis", axis_actions, 0, "Axis", "Axis to use to align bundle along");
1984 }
1985
1986 /********************** set scale operator *********************/
1987
1988 static int set_scale_exec(bContext *C, wmOperator *op)
1989 {
1990         SpaceClip *sc= CTX_wm_space_clip(C);
1991         MovieClip *clip= ED_space_clip(sc);
1992         MovieTrackingTrack *track;
1993         Scene *scene= CTX_data_scene(C);
1994         Object *parent= scene->camera;
1995         int tot= 0;
1996         float vec[2][3], mat[4][4], scale;
1997
1998         if(count_selected_bundles(C)!=2) {
1999                 BKE_report(op->reports, RPT_ERROR, "Two tracks with bundles should be selected to scale scene");
2000
2001                 return OPERATOR_CANCELLED;
2002         }
2003
2004         if(scene->camera->parent)
2005                 parent= scene->camera->parent;
2006
2007         BKE_get_tracking_mat(scene, mat);
2008
2009         track= clip->tracking.tracks.first;
2010         while(track) {
2011                 if(TRACK_SELECTED(track)) {
2012                         mul_v3_m4v3(vec[tot], mat, track->bundle_pos);
2013                         tot++;
2014                 }
2015
2016                 track= track->next;
2017         }
2018
2019         sub_v3_v3(vec[0], vec[1]);
2020
2021         if(len_v3(vec[0])>1e-5) {
2022                 scale= clip->tracking.settings.dist / len_v3(vec[0]);
2023
2024                 mul_v3_fl(parent->size, scale);
2025                 mul_v3_fl(parent->loc, scale);
2026
2027                 DAG_id_tag_update(&clip->id, 0);
2028                 DAG_id_tag_update(&parent->id, OB_RECALC_OB);
2029
2030                 WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
2031                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, NULL);
2032         }
2033
2034         return OPERATOR_FINISHED;
2035 }
2036
2037 void CLIP_OT_set_scale(wmOperatorType *ot)
2038 {
2039         /* identifiers */
2040         ot->name= "Set Scale";
2041         ot->description= "Set scale of scene";
2042         ot->idname= "CLIP_OT_set_scale";
2043
2044         /* api callbacks */
2045         ot->exec= set_scale_exec;
2046         ot->poll= space_clip_frame_camera_poll;
2047
2048         /* flags */
2049         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2050 }
2051
2052 /********************** set principal center operator *********************/
2053
2054 static int set_center_principal_exec(bContext *C, wmOperator *UNUSED(op))
2055 {
2056         SpaceClip *sc= CTX_wm_space_clip(C);
2057         MovieClip *clip= ED_space_clip(sc);
2058         int width, height;
2059
2060         BKE_movieclip_acquire_size(clip, &sc->user, &width, &height);
2061
2062         if(width==0 || height==0)
2063                 return OPERATOR_CANCELLED;
2064
2065         clip->tracking.camera.principal[0]= ((float)width)/2.0f;
2066         clip->tracking.camera.principal[1]= ((float)height)/2.0f;
2067
2068         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, clip);
2069
2070         return OPERATOR_FINISHED;
2071 }
2072
2073 void CLIP_OT_set_center_principal(wmOperatorType *ot)
2074 {
2075         /* identifiers */
2076         ot->name= "Set Principal to Center";
2077         ot->description= "Set principal point to center of footage";
2078         ot->idname= "CLIP_OT_set_center_principal";
2079
2080         /* api callbacks */
2081         ot->exec= set_center_principal_exec;
2082         ot->poll= space_clip_tracking_poll;
2083
2084         /* flags */
2085         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2086 }
2087
2088 /********************** hide tracks operator *********************/
2089
2090 static int hide_tracks_exec(bContext *C, wmOperator *op)
2091 {
2092         SpaceClip *sc= CTX_wm_space_clip(C);
2093         MovieClip *clip= ED_space_clip(sc);
2094         MovieTrackingTrack *track;
2095         int sel_type, unselected;
2096         void *sel;
2097
2098         unselected= RNA_boolean_get(op->ptr, "unselected");
2099
2100         BKE_movieclip_last_selection(clip, &sel_type, &sel);
2101
2102         track= clip->tracking.tracks.first;
2103         while(track) {
2104                 if(unselected==0 && TRACK_SELECTED(track)) {
2105                         track->flag|= TRACK_HIDDEN;
2106                 } else if(unselected==1 && !TRACK_SELECTED(track)) {
2107                         track->flag|= TRACK_HIDDEN;
2108                 }
2109
2110                 track= track->next;
2111         }
2112
2113         if(sel_type==MCLIP_SEL_TRACK) {
2114                 track= (MovieTrackingTrack *)sel;
2115
2116                 if(track->flag&TRACK_HIDDEN)
2117                         BKE_movieclip_set_selection(clip, MCLIP_SEL_NONE, NULL);
2118         }
2119
2120         WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, NULL);
2121
2122         return OPERATOR_FINISHED;
2123 }
2124
2125 void CLIP_OT_hide_tracks(wmOperatorType *ot)
2126 {
2127         /* identifiers */
2128         ot->name= "Hide Tracks";
2129         ot->description= "Hide selected tracks";
2130         ot->idname= "CLIP_OT_hide_tracks";
2131
2132         /* api callbacks */
2133         ot->exec= hide_tracks_exec;
2134         ot->poll= space_clip_tracking_poll;
2135
2136         /* flags */
2137         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2138
2139         /* properties */
2140         RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected tracks");
2141 }
2142
2143 /********************** hide tracks clear operator *********************/
2144
2145 static int hide_tracks_clear_exec(bContext *C, wmOperator *UNUSED(op))
2146 {
2147         SpaceClip *sc= CTX_wm_space_clip(C);
2148         MovieClip *clip= ED_space_clip(sc);
2149         MovieTrackingTrack *track;
2150
2151         track= clip->tracking.tracks.first;
2152         while(track) {
2153                 track->flag&= ~TRACK_HIDDEN;
2154
2155                 track= track->next;
2156         }
2157
2158         WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, NULL);
2159
2160         return OPERATOR_FINISHED;
2161 }
2162
2163 void CLIP_OT_hide_tracks_clear(wmOperatorType *ot)
2164 {
2165         /* identifiers */
2166         ot->name= "Hide Tracks Clear";
2167         ot->description= "Clear hide selected tracks";
2168         ot->idname= "CLIP_OT_hide_tracks_clear";
2169
2170         /* api callbacks */
2171         ot->exec= hide_tracks_clear_exec;
2172         ot->poll= space_clip_tracking_poll;
2173
2174         /* flags */
2175         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2176 }
2177
2178 /********************** detect features operator *********************/
2179
2180 static int detect_features_exec(bContext *C, wmOperator *UNUSED(op))
2181 {
2182         SpaceClip *sc= CTX_wm_space_clip(C);
2183         MovieClip *clip= ED_space_clip(sc);
2184         ImBuf *ibuf= BKE_movieclip_acquire_ibuf(clip, &sc->user);
2185         MovieTrackingTrack *track= clip->tracking.tracks.first;
2186
2187         /* deselect existing tracks */
2188         while(track) {
2189                 track->flag&= ~SELECT;
2190                 track->pat_flag&= ~SELECT;
2191                 track->search_flag&= ~SELECT;
2192
2193                 track= track->next;
2194         }
2195
2196         BKE_tracking_detect(&clip->tracking, ibuf, sc->user.framenr);
2197
2198         IMB_freeImBuf(ibuf);
2199
2200         BKE_movieclip_set_selection(clip, MCLIP_SEL_NONE, NULL);
2201         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, NULL);
2202
2203         return OPERATOR_FINISHED;
2204 }
2205
2206 void CLIP_OT_detect_features(wmOperatorType *ot)
2207 {
2208         /* identifiers */
2209         ot->name= "Detect Features";
2210         ot->description= "Automatically detect features to track";
2211         ot->idname= "CLIP_OT_detect_features";
2212
2213         /* api callbacks */
2214         ot->exec= detect_features_exec;
2215         ot->poll= space_clip_frame_poll;
2216
2217         /* flags */
2218         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2219 }
2220
2221 /********************** frame jump operator *********************/
2222
2223 static int frame_jump_exec(bContext *C, wmOperator *op)
2224 {
2225         Scene *scene= CTX_data_scene(C);
2226         SpaceClip *sc= CTX_wm_space_clip(C);
2227         MovieClip *clip= ED_space_clip(sc);
2228         MovieTrackingTrack *track;
2229         int end= RNA_boolean_get(op->ptr, "end");
2230         int sel_type, delta= end ? 1 : -1;
2231
2232         BKE_movieclip_last_selection(clip, &sel_type, (void**)&track);
2233
2234         if(sel_type!=MCLIP_SEL_TRACK)
2235                 return OPERATOR_CANCELLED;
2236
2237         while(BKE_tracking_has_marker(track, sc->user.framenr+delta)) {
2238                 sc->user.framenr+= delta;
2239         }
2240
2241         if(CFRA!=sc->user.framenr) {
2242                 CFRA= sc->user.framenr;
2243                 sound_seek_scene(C);
2244
2245                 WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
2246         }
2247
2248         WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, NULL);
2249
2250         return OPERATOR_FINISHED;
2251 }
2252
2253 void CLIP_OT_frame_jump(wmOperatorType *ot)
2254 {
2255         /* identifiers */
2256         ot->name= "Jump to Frame";
2257         ot->description= "Jump to special frame";
2258         ot->idname= "CLIP_OT_frame_jump";
2259
2260         /* api callbacks */
2261         ot->exec= frame_jump_exec;
2262         ot->poll= space_clip_frame_poll;
2263
2264         /* flags */
2265         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2266
2267         /* properties */
2268         RNA_def_boolean(ot->srna, "end", 0, "Last Frame", "Jump to the last frame of current track.");
2269 }
2270
2271 /********************** join tracks operator *********************/
2272
2273 static int join_tracks_exec(bContext *C, wmOperator *op)
2274 {
2275         SpaceClip *sc= CTX_wm_space_clip(C);
2276         MovieClip *clip= ED_space_clip(sc);
2277         MovieTrackingTrack *act_track, *track, *next;
2278         int sel_type;
2279
2280         BKE_movieclip_last_selection(clip, &sel_type, (void**)&act_track);
2281
2282         if(sel_type!=MCLIP_SEL_TRACK) {
2283                 BKE_report(op->reports, RPT_ERROR, "No active track to join to");
2284                 return OPERATOR_CANCELLED;
2285         }
2286
2287         track= clip->tracking.tracks.first;
2288         while(track) {
2289                 if(TRACK_SELECTED(track) && track!=act_track) {
2290                         if(!BKE_tracking_test_join_tracks(act_track, track)) {
2291                                 BKE_report(op->reports, RPT_ERROR, "Some selected tracks have got keyframed markers to the same frame");
2292                                 return OPERATOR_CANCELLED;
2293                         }
2294                 }
2295
2296                 track= track->next;
2297         }
2298
2299         track= clip->tracking.tracks.first;
2300         while(track) {
2301                 next= track->next;
2302
2303                 if(TRACK_SELECTED(track) && track!=act_track) {
2304                         BKE_tracking_join_tracks(act_track, track);
2305
2306                         BKE_tracking_free_track(track);
2307                         BLI_freelinkN(&clip->tracking.tracks, track);
2308                 }
2309
2310                 track= next;
2311         }
2312
2313         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, clip);
2314
2315         return OPERATOR_FINISHED;
2316 }
2317
2318 void CLIP_OT_join_tracks(wmOperatorType *ot)
2319 {
2320         /* identifiers */
2321         ot->name= "Join Tracks";
2322         ot->description= "Joint Selected Tracks";
2323         ot->idname= "CLIP_OT_join_tracks";
2324
2325         /* api callbacks */
2326         ot->exec= join_tracks_exec;
2327         ot->poll= space_clip_frame_poll;
2328
2329         /* flags */
2330         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2331 }
2332
2333 /********************** lock tracks operator *********************/
2334
2335 static int lock_tracks_exec(bContext *C, wmOperator *op)
2336 {
2337         SpaceClip *sc= CTX_wm_space_clip(C);
2338         MovieClip *clip= ED_space_clip(sc);
2339         MovieTracking *tracking= &clip->tracking;
2340         MovieTrackingTrack *track= tracking->tracks.first;
2341         int action= RNA_enum_get(op->ptr, "action");
2342
2343         while(track) {
2344                 if(TRACK_SELECTED(track)) {
2345                         if(action==0) track->flag|= TRACK_LOCKED;
2346                         else if(action==1) track->flag&= ~TRACK_LOCKED;
2347                         else track->flag^= TRACK_LOCKED;
2348                 }
2349
2350                 track= track->next;
2351         }
2352
2353         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
2354
2355         return OPERATOR_FINISHED;
2356 }
2357
2358 void CLIP_OT_lock_tracks(wmOperatorType *ot)
2359 {
2360         static EnumPropertyItem actions_items[] = {
2361                         {0, "LOCK", 0, "Lock", "Lock selected tracks"},
2362                         {1, "UNLOCK", 0, "Unlock", "Unlock selected tracks"},
2363                         {2, "TOGGLE", 0, "Toggle", "Toggle locked flag for selected tracks"},
2364                         {0, NULL, 0, NULL, NULL}
2365         };
2366
2367         /* identifiers */
2368         ot->name= "Lock Tracks";
2369         ot->description= "Lock/unlock selected tracks";
2370         ot->idname= "CLIP_OT_lock_tracks";
2371
2372         /* api callbacks */
2373         ot->exec= lock_tracks_exec;
2374         ot->poll= space_clip_tracking_poll;
2375
2376         /* flags */
2377         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2378
2379         /* properties */
2380         RNA_def_enum(ot->srna, "action", actions_items, 0, "Action", "Lock action to execute");
2381 }
2382
2383 /********************** track copy color operator *********************/
2384
2385 static int track_copy_color_exec(bContext *C, wmOperator *UNUSED(op))
2386 {
2387         SpaceClip *sc= CTX_wm_space_clip(C);
2388         MovieClip *clip= ED_space_clip(sc);
2389         MovieTrackingTrack *track, *sel;
2390         int sel_type;
2391
2392         BKE_movieclip_last_selection(clip, &sel_type, (void**)&sel);
2393
2394         if(sel_type!=MCLIP_SEL_TRACK)
2395                 return OPERATOR_CANCELLED;
2396
2397         track= clip->tracking.tracks.first;
2398         while(track) {
2399                 if(TRACK_SELECTED(track) && track!=sel) {
2400                         track->flag&= ~TRACK_CUSTOMCOLOR;
2401
2402                         if(sel->flag&TRACK_CUSTOMCOLOR) {
2403                                 copy_v3_v3(track->color, sel->color);
2404                                 track->flag|= TRACK_CUSTOMCOLOR;
2405                         }
2406                 }
2407
2408                 track= track->next;
2409         }
2410
2411         WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, clip);
2412
2413         return OPERATOR_FINISHED;
2414 }
2415
2416 void CLIP_OT_track_copy_color(wmOperatorType *ot)
2417 {
2418         /* identifiers */
2419         ot->name= "Copy Color";
2420         ot->description= "Copy color to all selected tracks";
2421         ot->idname= "CLIP_OT_track_copy_color";
2422
2423         /* api callbacks */
2424         ot->exec= track_copy_color_exec;
2425         ot->poll= space_clip_tracking_poll;
2426
2427         /* flags */
2428         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2429 }
2430
2431 /********************** add 2d stabilization tracks operator *********************/
2432
2433 static int stabilize_2d_add_exec(bContext *C, wmOperator *UNUSED(op))
2434 {
2435         SpaceClip *sc= CTX_wm_space_clip(C);
2436         MovieClip *clip= ED_space_clip(sc);
2437         MovieTracking *tracking= &clip->tracking;
2438         MovieTrackingTrack *track;
2439         MovieTrackingStabilization *stab= &tracking->stabilization;
2440
2441         track= tracking->tracks.first;
2442         while(track) {
2443                 if(TRACK_SELECTED(track)) {
2444                         track->flag|= TRACK_USE_2D_STAB;
2445                         stab->tot_track++;
2446                 }
2447
2448                 track= track->next;
2449         }
2450
2451         stab->ok= 0;
2452
2453         DAG_id_tag_update(&clip->id, 0);
2454         WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, clip);
2455
2456         return OPERATOR_FINISHED;
2457 }
2458
2459 void CLIP_OT_stabilize_2d_add(wmOperatorType *ot)
2460 {
2461         /* identifiers */
2462         ot->name= "Add Stabilization Tracks";
2463         ot->description= "Add selected tracks to 2D stabilization tool";
2464         ot->idname= "CLIP_OT_stabilize_2d_add";
2465
2466         /* api callbacks */
2467         ot->exec= stabilize_2d_add_exec;
2468         ot->poll= space_clip_tracking_poll;
2469
2470         /* flags */
2471         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2472 }
2473
2474 /********************** remove 2d stabilization tracks operator *********************/
2475
2476 static int stabilize_2d_remove_exec(bContext *C, wmOperator *UNUSED(op))
2477 {
2478         SpaceClip *sc= CTX_wm_space_clip(C);
2479         MovieClip *clip= ED_space_clip(sc);
2480         MovieTracking *tracking= &clip->tracking;
2481         MovieTrackingStabilization *stab= &tracking->stabilization;
2482         MovieTrackingTrack *track;
2483         int a= 0;
2484
2485         track= tracking->tracks.first;
2486         while(track) {
2487                 if(track->flag&TRACK_USE_2D_STAB) {
2488                         if(a==stab->act_track) {
2489                                 track->flag&= ~TRACK_USE_2D_STAB;
2490
2491                                 stab->act_track--;
2492                                 stab->tot_track--;
2493
2494                                 if(stab->act_track<0)
2495                                         stab->act_track= 0;
2496
2497                                 break;
2498                         }
2499
2500                         a++;
2501                 }
2502
2503                 track= track->next;
2504         }
2505
2506         stab->ok= 0;
2507
2508         DAG_id_tag_update(&clip->id, 0);
2509         WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, clip);
2510
2511         return OPERATOR_FINISHED;
2512 }
2513
2514 void CLIP_OT_stabilize_2d_remove(wmOperatorType *ot)
2515 {
2516         /* identifiers */
2517         ot->name= "Remove Stabilization Track";
2518         ot->description= "Remove selected track from stabilization";
2519         ot->idname= "CLIP_OT_stabilize_2d_remove";
2520
2521         /* api callbacks */
2522         ot->exec= stabilize_2d_remove_exec;
2523         ot->poll= space_clip_tracking_poll;
2524
2525         /* flags */
2526         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2527 }
2528
2529 /********************** select 2d stabilization tracks operator *********************/
2530
2531 static int stabilize_2d_select_exec(bContext *C, wmOperator *UNUSED(op))
2532 {
2533         SpaceClip *sc= CTX_wm_space_clip(C);
2534         MovieClip *clip= ED_space_clip(sc);
2535         MovieTracking *tracking= &clip->tracking;
2536         MovieTrackingTrack *track;
2537         int a= 0, area;
2538
2539         area= TRACK_AREA_POINT;
2540         if(sc->flag&SC_SHOW_MARKER_PATTERN) area|= TRACK_AREA_PAT;
2541         if(sc->flag&SC_SHOW_MARKER_SEARCH) area|= TRACK_AREA_SEARCH;
2542
2543         track= tracking->tracks.first;
2544         while(track) {
2545                 if(track->flag&TRACK_USE_2D_STAB) {
2546                         BKE_tracking_track_flag(track, area, SELECT, 0);
2547
2548                         a++;
2549                 }
2550
2551                 track= track->next;
2552         }
2553
2554         WM_event_add_notifier(C, NC_MOVIECLIP|ND_SELECT, clip);
2555
2556         return OPERATOR_FINISHED;
2557 }
2558
2559 void CLIP_OT_stabilize_2d_select(wmOperatorType *ot)
2560 {
2561         /* identifiers */
2562         ot->name= "Select Stabilization Tracks";
2563         ot->description= "Select track whic hare used for stabilization";
2564         ot->idname= "CLIP_OT_stabilize_2d_select";
2565
2566         /* api callbacks */
2567         ot->exec= stabilize_2d_select_exec;
2568         ot->poll= space_clip_tracking_poll;
2569
2570         /* flags */
2571         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2572 }