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
53 #include "WM_api.h"
54 #include "WM_types.h"
55
56 #include "ED_screen.h"
57 #include "ED_clip.h"
58 #include "ED_keyframing.h"
59
60 #include "IMB_imbuf_types.h"
61 #include "IMB_imbuf.h"
62
63 #include "UI_interface.h"
64
65 #include "RNA_access.h"
66 #include "RNA_define.h"
67
68 #include "PIL_time.h"
69
70 #include "UI_view2d.h"
71
72 #include "clip_intern.h"        // own include
73
74 /** \file blender/editors/space_clip/tracking_ops.c
75  *  \ingroup spclip
76  */
77
78 static int space_clip_tracking_poll(bContext *C)
79 {
80         SpaceClip *sc= CTX_wm_space_clip(C);
81
82         if(sc && sc->clip)
83                 return 1;
84
85         return 0;
86 }
87
88 static int space_clip_frame_poll(bContext *C)
89 {
90         SpaceClip *sc= CTX_wm_space_clip(C);
91
92         if(sc) {
93                 MovieClip *clip= ED_space_clip(sc);
94
95                 if(clip)
96                         return BKE_movieclip_has_frame(clip, &sc->user);
97         }
98
99         return 0;
100 }
101
102 static int space_clip_frame_camera_poll(bContext *C)
103 {
104         Scene *scene= CTX_data_scene(C);
105
106         if(space_clip_frame_poll(C)) {
107                 return scene->camera != NULL;
108         }
109
110         return 0;
111 }
112
113 static int space_clip_camera_poll(bContext *C)
114 {
115         SpaceClip *sc= CTX_wm_space_clip(C);
116         Scene *scene= CTX_data_scene(C);
117
118         if(sc && sc->clip && scene->camera)
119                 return 1;
120
121         return 0;
122 }
123
124 /********************** add marker operator *********************/
125
126 static void add_marker(SpaceClip *sc, float x, float y)
127 {
128         MovieClip *clip= ED_space_clip(sc);
129         MovieTrackingTrack *track;
130         int width, height;
131
132         ED_space_clip_size(sc, &width, &height);
133
134         track= BKE_tracking_add_track(&clip->tracking, x, y, sc->user.framenr, width, height);
135
136         BKE_movieclip_select_track(clip, track, TRACK_AREA_ALL, 0);
137         BKE_movieclip_set_selection(clip, MCLIP_SEL_TRACK, track);
138 }
139
140 static int add_marker_exec(bContext *C, wmOperator *op)
141 {
142         SpaceClip *sc= CTX_wm_space_clip(C);
143         MovieClip *clip= ED_space_clip(sc);
144         float pos[2];
145         int width, height;
146
147         ED_space_clip_size(sc, &width, &height);
148         if(!width || !height)
149                 return OPERATOR_CANCELLED;
150
151         RNA_float_get_array(op->ptr, "location", pos);
152
153         add_marker(sc, pos[0], pos[1]);
154
155         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, clip);
156
157         return OPERATOR_FINISHED;
158 }
159
160 static void mouse_pos(bContext *C, wmEvent *event, float co[2])
161 {
162         ARegion *ar= CTX_wm_region(C);
163         SpaceClip *sc= CTX_wm_space_clip(C);
164         int sx, sy;
165
166         UI_view2d_to_region_no_clip(&ar->v2d, 0.0f, 0.0f, &sx, &sy);
167         co[0]= ((float)event->mval[0]-sx)/sc->zoom;
168         co[1]= ((float)event->mval[1]-sy)/sc->zoom;
169 }
170
171 static int add_marker_invoke(bContext *C, wmOperator *op, wmEvent *event)
172 {
173         SpaceClip *sc= CTX_wm_space_clip(C);
174         int width, height;
175         float co[2];
176
177         ED_space_clip_size(sc, &width, &height);
178         if(!width || !height)
179                 return OPERATOR_CANCELLED;
180
181         mouse_pos(C, event, co);
182         co[0]/= width;
183         co[1]/= height;
184
185         RNA_float_set_array(op->ptr, "location", co);
186
187         return add_marker_exec(C, op);
188 }
189
190 void CLIP_OT_add_marker(wmOperatorType *ot)
191 {
192         /* identifiers */
193         ot->name= "Add Marker";
194         ot->idname= "CLIP_OT_add_marker";
195         ot->description= "Place new marker at specified location";
196
197         /* api callbacks */
198         ot->invoke= add_marker_invoke;
199         ot->exec= add_marker_exec;
200         ot->poll= space_clip_tracking_poll;
201
202         /* flags */
203         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
204
205         /* properties */
206         RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MIN, FLT_MAX,
207                 "Location", "Location of marker on frame.", -1.f, 1.f);
208 }
209
210 /********************** delete track operator *********************/
211
212 static int delete_track_exec(bContext *C, wmOperator *UNUSED(op))
213 {
214         SpaceClip *sc= CTX_wm_space_clip(C);
215         MovieClip *clip= ED_space_clip(sc);
216         MovieTrackingTrack *track= clip->tracking.tracks.first, *next;
217         int has_bundle= 0;
218
219         while(track) {
220                 next= track->next;
221
222                 if(TRACK_VIEW_SELECTED(track)) {
223                         if(track->flag&TRACK_HAS_BUNDLE)
224                                 has_bundle= 1;
225
226                         BKE_tracking_free_track(track);
227                         BLI_freelinkN(&clip->tracking.tracks, track);
228                 }
229
230                 track= next;
231         }
232
233         BKE_movieclip_set_selection(clip, MCLIP_SEL_NONE, NULL);
234         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, clip);
235
236         if(has_bundle)
237                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, NULL);
238
239         return OPERATOR_FINISHED;
240 }
241
242 void CLIP_OT_delete_track(wmOperatorType *ot)
243 {
244         /* identifiers */
245         ot->name= "Delete Track";
246         ot->idname= "CLIP_OT_delete_track";
247         ot->description= "Delete selected tracks";
248
249         /* api callbacks */
250         ot->invoke= WM_operator_confirm;
251         ot->exec= delete_track_exec;
252         ot->poll= space_clip_tracking_poll;
253
254         /* flags */
255         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
256 }
257
258 /********************** delete marker operator *********************/
259
260 static int delete_marker_exec(bContext *C, wmOperator *UNUSED(op))
261 {
262         SpaceClip *sc= CTX_wm_space_clip(C);
263         MovieClip *clip= ED_space_clip(sc);
264         MovieTrackingTrack *track= clip->tracking.tracks.first, *next;
265         int framenr= sc->user.framenr, sel_type;
266         void *sel;
267
268         BKE_movieclip_last_selection(clip, &sel_type, &sel);
269
270         while(track) {
271                 next= track->next;
272
273                 if(TRACK_VIEW_SELECTED(track)) {
274                         MovieTrackingMarker *marker= BKE_tracking_exact_marker(track, framenr);
275
276                         if(marker) {
277                                 if(track->markersnr==1) {
278                                         if(sel_type==MCLIP_SEL_TRACK && sel==track)
279                                                 BKE_movieclip_set_selection(clip, MCLIP_SEL_NONE, NULL);
280
281                                         BKE_tracking_free_track(track);
282                                         BLI_freelinkN(&clip->tracking.tracks, track);
283                                 } else {
284                                         BKE_tracking_delete_marker(track, framenr);
285                                 }
286                         }
287                 }
288
289                 track= next;
290         }
291
292         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, clip);
293
294         return OPERATOR_FINISHED;
295 }
296
297 void CLIP_OT_delete_marker(wmOperatorType *ot)
298 {
299         /* identifiers */
300         ot->name= "Delete Marker";
301         ot->idname= "CLIP_OT_delete_marker";
302         ot->description= "Delete marker for current frame from selected tracks";
303
304         /* api callbacks */
305         ot->invoke= WM_operator_confirm;
306         ot->exec= delete_marker_exec;
307         ot->poll= space_clip_tracking_poll;
308
309         /* flags */
310         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
311 }
312
313 /********************** mouse select operator *********************/
314
315 static int mouse_on_side(float co[2], float x1, float y1, float x2, float y2, float epsx, float epsy)
316 {
317         if(x1>x2) SWAP(float, x1, x2);
318         if(y1>y2) SWAP(float, y1, y2);
319
320         return (co[0]>=x1-epsx && co[0]<=x2+epsx) && (co[1]>=y1-epsy && co[1]<=y2+epsy);
321 }
322
323 static int mouse_on_rect(float co[2], float pos[2], float min[2], float max[2], float epsx, float epsy)
324 {
325         return mouse_on_side(co, pos[0]+min[0], pos[1]+min[1], pos[0]+max[0], pos[1]+min[1], epsx, epsy) ||
326                mouse_on_side(co, pos[0]+min[0], pos[1]+min[1], pos[0]+min[0], pos[1]+max[1], epsx, epsy) ||
327                mouse_on_side(co, pos[0]+min[0], pos[1]+max[1], pos[0]+max[0], pos[1]+max[1], epsx, epsy) ||
328                mouse_on_side(co, pos[0]+max[0], pos[1]+min[1], pos[0]+max[0], pos[1]+max[1], epsx, epsy);
329 }
330
331 static int track_mouse_area(SpaceClip *sc, float co[2], MovieTrackingTrack *track)
332 {
333         MovieTrackingMarker *marker= BKE_tracking_get_marker(track, sc->user.framenr);
334         float epsx, epsy;
335         int width, height;
336
337         ED_space_clip_size(sc, &width, &height);
338
339         epsx= MIN4(track->pat_min[0]-track->search_min[0], track->search_max[0]-track->pat_max[0],
340                    fabsf(track->pat_min[0]), fabsf(track->pat_max[0])) / 2;
341         epsy= MIN4(track->pat_min[1]-track->search_min[1], track->search_max[1]-track->pat_max[1],
342                    fabsf(track->pat_min[1]), fabsf(track->pat_max[1])) / 2;
343
344         epsx= MAX2(epsy, 2.0 / width);
345         epsy= MAX2(epsy, 2.0 / height);
346
347         if((marker->flag&MARKER_DISABLED)==0) {
348                 if(fabsf(co[0]-marker->pos[0])< epsx && fabsf(co[1]-marker->pos[1])<=epsy)
349                         return TRACK_AREA_POINT;
350
351                 if(sc->flag&SC_SHOW_MARKER_PATTERN)
352                         if(mouse_on_rect(co, marker->pos, track->pat_min, track->pat_max, epsx, epsy))
353                                 return TRACK_AREA_PAT;
354         }
355
356         if(sc->flag&SC_SHOW_MARKER_SEARCH)
357                 if(mouse_on_rect(co, marker->pos, track->search_min, track->search_max, epsx, epsy))
358                         return TRACK_AREA_SEARCH;
359
360         return TRACK_AREA_NONE;
361 }
362
363 static float dist_to_rect(float co[2], float pos[2], float min[2], float max[2])
364 {
365         float d1, d2, d3, d4;
366         float p[2]= {co[0]-pos[0], co[1]-pos[1]};
367         float v1[2]= {min[0], min[1]}, v2[2]= {max[0], min[1]},
368               v3[2]= {max[0], max[1]}, v4[2]= {min[0], max[1]};
369
370         d1= dist_to_line_segment_v2(p, v1, v2);
371         d2= dist_to_line_segment_v2(p, v2, v3);
372         d3= dist_to_line_segment_v2(p, v3, v4);
373         d4= dist_to_line_segment_v2(p, v4, v1);
374
375         return MIN4(d1, d2, d3, d4);
376 }
377
378 static MovieTrackingTrack *find_nearest_track(SpaceClip *sc, MovieClip *clip, float co[2])
379 {
380         MovieTrackingTrack *track= NULL, *cur;
381         float mindist= 0.0f;
382
383         cur= clip->tracking.tracks.first;
384         while(cur) {
385                 MovieTrackingMarker *marker= BKE_tracking_get_marker(cur, sc->user.framenr);
386
387                 if(TRACK_VISIBLE(cur) && MARKER_VISIBLE(sc, marker)) {
388                         float dist, d1, d2, d3;
389
390                         d1= sqrtf((co[0]-marker->pos[0])*(co[0]-marker->pos[0])+
391                                           (co[1]-marker->pos[1])*(co[1]-marker->pos[1])); /* distance to marker point */
392                         d2= dist_to_rect(co, marker->pos, cur->pat_min, cur->pat_max); /* distance to search boundbox */
393                         d3= dist_to_rect(co, marker->pos, cur->search_min, cur->search_max); /* distance to search boundbox */
394
395                         /* choose minimal distance. useful for cases of overlapped markers. */
396                         dist= MIN3(d1, d2, d3);
397
398                         if(track==NULL || dist<mindist) {
399                                 track= cur;
400                                 mindist= dist;
401                         }
402                 }
403
404                 cur= cur->next;
405         }
406
407         return track;
408 }
409
410 static int mouse_select(bContext *C, float co[2], int extend)
411 {
412         SpaceClip *sc= CTX_wm_space_clip(C);
413         MovieClip *clip= ED_space_clip(sc);
414         MovieTrackingTrack *track= NULL;        /* selected marker */
415
416         track= find_nearest_track(sc, clip, co);
417
418         if(track) {
419                 int area= track_mouse_area(sc, co, track);
420
421                 if(!extend || !TRACK_SELECTED(track))
422                         area= TRACK_AREA_ALL;
423
424                 if(extend && TRACK_AREA_SELECTED(track, area)) {
425                         BKE_movieclip_deselect_track(clip, track, area);
426                 } else {
427                         if(area==TRACK_AREA_POINT) area= TRACK_AREA_ALL;
428
429                         BKE_movieclip_select_track(clip, track, area, extend);
430                         BKE_movieclip_set_selection(clip, MCLIP_SEL_TRACK, track);
431                 }
432         }
433
434         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, NULL);
435
436         return OPERATOR_FINISHED;
437 }
438
439 static int select_exec(bContext *C, wmOperator *op)
440 {
441         float co[2];
442         int extend;
443
444         RNA_float_get_array(op->ptr, "location", co);
445         extend= RNA_boolean_get(op->ptr, "extend");
446
447         return mouse_select(C, co, extend);
448 }
449
450 static int select_invoke(bContext *C, wmOperator *op, wmEvent *event)
451 {
452         ARegion *ar= CTX_wm_region(C);
453         float co[2];
454
455         UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
456         RNA_float_set_array(op->ptr, "location", co);
457
458         return select_exec(C, op);
459 }
460
461 void CLIP_OT_select(wmOperatorType *ot)
462 {
463         /* identifiers */
464         ot->name= "Select";
465         ot->description= "Select tracking markers";
466         ot->idname= "CLIP_OT_select";
467
468         /* api callbacks */
469         ot->exec= select_exec;
470         ot->invoke= select_invoke;
471         ot->poll= space_clip_tracking_poll;
472
473         /* flags */
474         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
475
476         /* properties */
477         RNA_def_boolean(ot->srna, "extend", 0,
478                 "Extend", "Extend selection rather than clearing the existing selection.");
479         RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
480                 "Location", "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds.", -100.0f, 100.0f);
481 }
482
483 /********************** border select operator *********************/
484
485 static int border_select_exec(bContext *C, wmOperator *op)
486 {
487         SpaceClip *sc= CTX_wm_space_clip(C);
488         MovieClip *clip= ED_space_clip(sc);
489         MovieTrackingTrack *track;
490         ARegion *ar= CTX_wm_region(C);
491         rcti rect;
492         rctf rectf;
493         int change= 0, mode;
494
495         /* get rectangle from operator */
496         rect.xmin= RNA_int_get(op->ptr, "xmin");
497         rect.ymin= RNA_int_get(op->ptr, "ymin");
498         rect.xmax= RNA_int_get(op->ptr, "xmax");
499         rect.ymax= RNA_int_get(op->ptr, "ymax");
500
501         UI_view2d_region_to_view(&ar->v2d, rect.xmin, rect.ymin, &rectf.xmin, &rectf.ymin);
502         UI_view2d_region_to_view(&ar->v2d, rect.xmax, rect.ymax, &rectf.xmax, &rectf.ymax);
503
504         mode= RNA_int_get(op->ptr, "gesture_mode");
505
506         /* do actual selection */
507         track= clip->tracking.tracks.first;
508         while(track) {
509                 if(TRACK_VISIBLE(track)) {
510                         MovieTrackingMarker *marker= BKE_tracking_get_marker(track, sc->user.framenr);
511
512                         if(MARKER_VISIBLE(sc, marker) && BLI_in_rctf(&rectf, marker->pos[0], marker->pos[1])) {
513                                 BKE_tracking_track_flag(track, TRACK_AREA_ALL, SELECT, mode!=GESTURE_MODAL_SELECT);
514
515                                 change= 1;
516                         }
517                 }
518
519                 track= track->next;
520         }
521
522         BKE_movieclip_set_selection(clip, MCLIP_SEL_NONE, NULL);
523
524         if(change) {
525                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, NULL);
526
527                 return OPERATOR_FINISHED;
528         }
529
530         return OPERATOR_CANCELLED;
531 }
532
533 void CLIP_OT_select_border(wmOperatorType *ot)
534 {
535         /* identifiers */
536         ot->name= "Border Select";
537         ot->description= "Select markers using border selection";
538         ot->idname= "CLIP_OT_select_border";
539
540         /* api callbacks */
541         ot->invoke= WM_border_select_invoke;
542         ot->exec= border_select_exec;
543         ot->modal= WM_border_select_modal;
544         ot->poll= space_clip_tracking_poll;
545
546         /* flags */
547         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
548
549         /* properties */
550         WM_operator_properties_gesture_border(ot, FALSE);
551 }
552
553 /********************** circle select operator *********************/
554
555 static int marker_inside_ellipse(MovieTrackingMarker *marker, float offset[2], float ellipse[2])
556 {
557         /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */
558         float x, y;
559
560         x= (marker->pos[0] - offset[0])*ellipse[0];
561         y= (marker->pos[1] - offset[1])*ellipse[1];
562
563         return x*x + y*y < 1.0f;
564 }
565
566 static int circle_select_exec(bContext *C, wmOperator *op)
567 {
568         SpaceClip *sc= CTX_wm_space_clip(C);
569         MovieClip *clip= ED_space_clip(sc);
570         ARegion *ar= CTX_wm_region(C);
571         MovieTrackingTrack *track;
572         int x, y, radius, width, height, mode, change= 0;
573         float zoomx, zoomy, offset[2], ellipse[2];
574
575         /* get operator properties */
576         x= RNA_int_get(op->ptr, "x");
577         y= RNA_int_get(op->ptr, "y");
578         radius= RNA_int_get(op->ptr, "radius");
579
580         mode= RNA_int_get(op->ptr, "gesture_mode");
581
582         /* compute ellipse and position in unified coordinates */
583         ED_space_clip_size(sc, &width, &height);
584         ED_space_clip_zoom(sc, ar, &zoomx, &zoomy);
585
586         ellipse[0]= width*zoomx/radius;
587         ellipse[1]= height*zoomy/radius;
588
589         UI_view2d_region_to_view(&ar->v2d, x, y, &offset[0], &offset[1]);
590
591         /* do selection */
592         track= clip->tracking.tracks.first;
593         while(track) {
594                 if(TRACK_VISIBLE(track)) {
595                         MovieTrackingMarker *marker= BKE_tracking_get_marker(track, sc->user.framenr);
596
597                         if(MARKER_VISIBLE(sc, marker) && marker_inside_ellipse(marker, offset, ellipse)) {
598                                 BKE_tracking_track_flag(track, TRACK_AREA_ALL, SELECT, mode!=GESTURE_MODAL_SELECT);
599
600                                 change= 1;
601                         }
602                 }
603
604                 track= track->next;
605         }
606
607         BKE_movieclip_set_selection(clip, MCLIP_SEL_NONE, NULL);
608
609         if(change) {
610                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, NULL);
611
612                 return OPERATOR_FINISHED;
613         }
614
615         return OPERATOR_CANCELLED;
616 }
617
618 void CLIP_OT_select_circle(wmOperatorType *ot)
619 {
620         /* identifiers */
621         ot->name= "Circle Select";
622         ot->description= "Select markers using circle selection";
623         ot->idname= "CLIP_OT_select_circle";
624
625         /* api callbacks */
626         ot->invoke= WM_gesture_circle_invoke;
627         ot->modal= WM_gesture_circle_modal;
628         ot->exec= circle_select_exec;
629         ot->poll= space_clip_tracking_poll;
630
631         /* flags */
632         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
633
634         /* properties */
635         RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
636         RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
637         RNA_def_int(ot->srna, "radius", 0, INT_MIN, INT_MAX, "Radius", "", INT_MIN, INT_MAX);
638         RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Gesture Mode", "", INT_MIN, INT_MAX);
639 }
640
641 /********************** select all operator *********************/
642
643 static int select_all_exec(bContext *C, wmOperator *op)
644 {
645         SpaceClip *sc= CTX_wm_space_clip(C);
646         MovieClip *clip= ED_space_clip(sc);
647         MovieTrackingTrack *track= NULL;        /* selected track */
648         int action= RNA_enum_get(op->ptr, "action");
649         int sel_type, framenr= sc->user.framenr;
650         void *sel;
651
652         if(action == SEL_TOGGLE){
653                 action= SEL_SELECT;
654                 track= clip->tracking.tracks.first;
655                 while(track) {
656                         if(TRACK_VIEW_SELECTED(track)) {
657                                 action= SEL_DESELECT;
658                                 break;
659                         }
660
661                         track= track->next;
662                 }
663         }
664
665         track= clip->tracking.tracks.first;
666         while(track) {
667                 if(TRACK_VISIBLE(track)) {
668                         MovieTrackingMarker *marker= BKE_tracking_get_marker(track, framenr);
669
670                         if(marker && MARKER_VISIBLE(sc, marker)) {
671                                 switch (action) {
672                                         case SEL_SELECT:
673                                                 track->flag|= SELECT;
674                                                 track->pat_flag|= SELECT;
675                                                 track->search_flag|= SELECT;
676                                                 break;
677                                         case SEL_DESELECT:
678                                                 track->flag&= ~SELECT;
679                                                 track->pat_flag&= ~SELECT;
680                                                 track->search_flag&= ~SELECT;
681                                                 break;
682                                         case SEL_INVERT:
683                                                 track->flag^= SELECT;
684                                                 track->pat_flag^= SELECT;
685                                                 track->search_flag^= SELECT;
686                                                 break;
687                                 }
688                         }
689                 }
690
691                 track= track->next;
692         }
693
694         BKE_movieclip_last_selection(clip, &sel_type, &sel);
695         if(sel_type==MCLIP_SEL_TRACK)
696                 if(!TRACK_SELECTED(((MovieTrackingTrack*)sel)))
697                         BKE_movieclip_set_selection(clip, MCLIP_SEL_NONE, NULL);
698
699         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, NULL);
700
701         return OPERATOR_FINISHED;
702 }
703
704 void CLIP_OT_select_all(wmOperatorType *ot)
705 {
706         /* identifiers */
707         ot->name= "Select or Deselect All";
708         ot->description= "Change selection of all tracking markers";
709         ot->idname= "CLIP_OT_select_all";
710
711         /* api callbacks */
712         ot->exec= select_all_exec;
713         ot->poll= space_clip_tracking_poll;
714
715         /* flags */
716         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
717
718         WM_operator_properties_select_all(ot);
719 }
720
721 /********************** track operator *********************/
722
723 typedef struct TrackMarkersJob {
724         struct MovieTrackingContext *context;   /* tracking context */
725         int sfra, efra, lastfra;        /* Start, end and recently tracked frames */
726         int backwards;                          /* Backwards tracking flag */
727         MovieClip *clip;                        /* Clip which is tracking */
728         float delay;                            /* Delay in milliseconds to allow tracking at fixed FPS */
729
730         struct Main *main;
731         struct Scene *scene;
732         struct bScreen *screen;
733 } TrackMarkersJob;
734
735 static int track_markers_testbreak(void)
736 {
737         return G.afbreek;
738 }
739
740 static void track_init_markers(SpaceClip *sc, MovieClip *clip)
741 {
742         MovieTrackingTrack *track;
743         int framenr= sc->user.framenr;
744
745         track= clip->tracking.tracks.first;
746         while(track) {
747                 if(TRACK_VISIBLE(track))
748                         BKE_tracking_ensure_marker(track, framenr);
749
750                 track= track->next;
751         }
752 }
753
754 static void track_markers_initjob(bContext *C, TrackMarkersJob *tmj, int backwards)
755 {
756         SpaceClip *sc= CTX_wm_space_clip(C);
757         MovieClip *clip= ED_space_clip(sc);
758         Scene *scene= CTX_data_scene(C);
759         MovieTrackingSettings *settings= &clip->tracking.settings;
760
761         tmj->sfra= sc->user.framenr;
762         tmj->clip= clip;
763         tmj->backwards= backwards;
764
765         if(backwards) tmj->efra= SFRA;
766         else tmj->efra= EFRA;
767
768         /* limit frames to be tracked by user setting */
769         if(settings->flag&TRACKING_FRAMES_LIMIT) {
770                 if(backwards) tmj->efra= MAX2(tmj->efra, tmj->sfra-settings->frames_limit);
771                 else tmj->efra= MIN2(tmj->efra, tmj->sfra+settings->frames_limit);
772         }
773
774         if(settings->speed!=TRACKING_SPEED_FASTEST) {
775                 tmj->delay= 1.0f/scene->r.frs_sec*1000.0f;
776
777                 if(settings->speed==TRACKING_SPEED_HALF) tmj->delay*= 2;
778                 else if(settings->speed==TRACKING_SPEED_QUARTER) tmj->delay*= 4;
779         }
780
781         track_init_markers(sc, clip);
782
783         tmj->context= BKE_tracking_context_new(clip, &sc->user, backwards);
784
785         clip->tracking_context= tmj->context;
786
787         tmj->lastfra= tmj->sfra;
788
789         /* XXX: silly to store this, but this data is needed to update scene and movieclip
790                 frame numbers when tracking is finished. This introduces better feedback for artists.
791                 Maybe there's another way to solve this problem, but can't think better way atm.
792                 Anyway, this way isn't more unstable as animation rendering animation
793                 which uses the same approach (except storing screen). */
794         tmj->scene= scene;
795         tmj->main= CTX_data_main(C);
796         tmj->screen= CTX_wm_screen(C);
797 }
798
799 static void track_markers_startjob(void *tmv, short *UNUSED(stop), short *do_update, float *progress)
800 {
801         TrackMarkersJob *tmj= (TrackMarkersJob *)tmv;
802         int framenr= tmj->sfra;
803
804         while(framenr != tmj->efra) {
805                 if(tmj->delay>0) {
806                         /* tracking should happen with fixed fps. Calculate time
807                            using current timer value before tracking frame and after.
808
809                            Small (and maybe unneeded optimization): do not calculate exec_time
810                            for "Fastest" tracking */
811
812                         double start_time= PIL_check_seconds_timer(), exec_time;
813
814                         if(!BKE_tracking_next(tmj->context))
815                                 break;
816
817                         exec_time= PIL_check_seconds_timer()-start_time;
818                         if(tmj->delay>exec_time)
819                                 PIL_sleep_ms(tmj->delay-exec_time);
820                 } else if(!BKE_tracking_next(tmj->context))
821                                 break;
822
823                 *do_update= 1;
824                 *progress=(float)(framenr-tmj->sfra) / (tmj->efra-tmj->sfra);
825
826                 if(tmj->backwards) framenr--;
827                 else framenr++;
828
829                 tmj->lastfra= framenr;
830
831                 if(track_markers_testbreak())
832                         break;
833         }
834 }
835
836 static void track_markers_updatejob(void *tmv)
837 {
838         TrackMarkersJob *tmj= (TrackMarkersJob *)tmv;
839
840         BKE_tracking_sync(tmj->context);
841 }
842
843 static void track_markers_freejob(void *tmv)
844 {
845         TrackMarkersJob *tmj= (TrackMarkersJob *)tmv;
846
847         tmj->clip->tracking_context= NULL;
848         tmj->scene->r.cfra= tmj->lastfra;
849         ED_update_for_newframe(tmj->main, tmj->scene, tmj->screen, 0);
850
851         BKE_tracking_sync(tmj->context);
852         BKE_tracking_context_free(tmj->context);
853
854         MEM_freeN(tmj);
855
856         WM_main_add_notifier(NC_SCENE|ND_FRAME, tmj->scene);
857 }
858
859 static int track_markers_exec(bContext *C, wmOperator *op)
860 {
861         SpaceClip *sc= CTX_wm_space_clip(C);
862         MovieClip *clip= ED_space_clip(sc);
863         Scene *scene= CTX_data_scene(C);
864         struct MovieTrackingContext *context;
865         int framenr= sc->user.framenr;
866         int sfra= framenr, efra;
867         int backwards= RNA_boolean_get(op->ptr, "backwards");
868         int sequence= RNA_boolean_get(op->ptr, "sequence");
869         MovieTrackingSettings *settings= &clip->tracking.settings;
870
871         if(backwards) efra= SFRA;
872         else efra= EFRA;
873
874         /* limit frames to be tracked by user setting */
875         if(settings->flag&TRACKING_FRAMES_LIMIT) {
876                 if(backwards) efra= MAX2(efra, sfra-settings->frames_limit);
877                 else efra= MIN2(efra, sfra+settings->frames_limit);
878         }
879
880         track_init_markers(sc, clip);
881
882         context= BKE_tracking_context_new(clip, &sc->user, backwards);
883
884         while(framenr != efra) {
885                 if(!BKE_tracking_next(context))
886                         break;
887
888                 if(backwards) framenr--;
889                 else framenr++;
890
891                 if(!sequence)
892                         break;
893         }
894
895         BKE_tracking_sync(context);
896         BKE_tracking_context_free(context);
897
898         /* update scene current frame to the lastes tracked frame */
899         scene->r.cfra= framenr;
900
901         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
902         WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
903
904         return OPERATOR_FINISHED;
905 }
906
907 static int track_markers_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
908 {
909         TrackMarkersJob *tmj;
910         SpaceClip *sc= CTX_wm_space_clip(C);
911         MovieClip *clip= ED_space_clip(sc);
912         wmJob *steve;
913         Scene *scene= CTX_data_scene(C);
914         int backwards= RNA_boolean_get(op->ptr, "backwards");
915         int sequence= RNA_boolean_get(op->ptr, "sequence");
916
917         if(clip->tracking_context)
918                 return OPERATOR_CANCELLED;
919
920         if(!sequence)
921                 return track_markers_exec(C, op);
922
923         tmj= MEM_callocN(sizeof(TrackMarkersJob), "TrackMarkersJob data");
924         track_markers_initjob(C, tmj, backwards);
925
926         /* setup job */
927         steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, "Track Markers", WM_JOB_EXCL_RENDER|WM_JOB_PRIORITY|WM_JOB_PROGRESS);
928         WM_jobs_customdata(steve, tmj, track_markers_freejob);
929
930         /* if there's delay set in tracking job, tracking should happen
931            with fixed FPS. To deal with editor refresh we have to syncronize
932            tracks from job and tracks in clip. Do this in timer callback
933            to prevent threading conflicts. */
934         if(tmj->delay>0) WM_jobs_timer(steve, tmj->delay/1000.0f, NC_MOVIECLIP|NA_EVALUATED, 0);
935         else WM_jobs_timer(steve, 0.2, NC_MOVIECLIP|NA_EVALUATED, 0);
936
937         WM_jobs_callbacks(steve, track_markers_startjob, NULL, track_markers_updatejob, NULL);
938
939         G.afbreek= 0;
940
941         WM_jobs_start(CTX_wm_manager(C), steve);
942         WM_cursor_wait(0);
943
944         /* add modal handler for ESC */
945         WM_event_add_modal_handler(C, op);
946
947         return OPERATOR_RUNNING_MODAL;
948 }
949
950 static int track_markers_modal(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
951 {
952         /* no running blender, remove handler and pass through */
953         if(0==WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C)))
954                 return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
955
956         /* running tracking */
957         switch (event->type) {
958                 case ESCKEY:
959                         return OPERATOR_RUNNING_MODAL;
960                         break;
961         }
962
963         return OPERATOR_PASS_THROUGH;
964 }
965
966 void CLIP_OT_track_markers(wmOperatorType *ot)
967 {
968         /* identifiers */
969         ot->name= "Track Markers";
970         ot->description= "Track sleected markers";
971         ot->idname= "CLIP_OT_track_markers";
972
973         /* api callbacks */
974         ot->exec= track_markers_exec;
975         ot->invoke= track_markers_invoke;
976         ot->poll= space_clip_frame_poll;
977         ot->modal= track_markers_modal;
978
979         /* flags */
980         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
981
982         /* properties */
983         RNA_def_boolean(ot->srna, "backwards", 0, "Backwards", "Do backwards tarcking");
984         RNA_def_boolean(ot->srna, "sequence", 0, "Track Sequence", "Track marker during image sequence rather than single image");
985 }
986
987 /********************** solve camera operator *********************/
988
989 static int check_solve_tarck_count(MovieTracking *tracking)
990 {
991         int tot= 0;
992         int frame1= tracking->settings.keyframe1, frame2= tracking->settings.keyframe2;
993         MovieTrackingTrack *track;
994
995         track= tracking->tracks.first;
996         while(track) {
997                 if(BKE_tracking_has_marker(track, frame1))
998                         if(BKE_tracking_has_marker(track, frame2))
999                                 tot++;
1000
1001                 track= track->next;
1002         }
1003
1004         return tot>=10;
1005 }
1006
1007 static int solve_camera_exec(bContext *C, wmOperator *op)
1008 {
1009         SpaceClip *sc= CTX_wm_space_clip(C);
1010         MovieClip *clip= ED_space_clip(sc);
1011         Scene *scene= CTX_data_scene(C);
1012
1013         if(!check_solve_tarck_count(&clip->tracking)) {
1014                 BKE_report(op->reports, RPT_ERROR, "At least 10 tracks on both of keyframes are needed for reconstruction");
1015                 return OPERATOR_CANCELLED;
1016         }
1017
1018         BKE_tracking_solve_reconstruction(clip);
1019
1020         scene->clip= clip;
1021
1022         if(!scene->camera)
1023                 scene->camera= scene_find_camera(scene);
1024
1025         if(scene->camera) {
1026                 MovieTracking *tracking= &clip->tracking;
1027                 float focal= tracking->camera.focal;
1028
1029                 /* set blender camera focal length so result would look fine there */
1030                 if(focal) {
1031                         Camera *camera= (Camera*)scene->camera->data;
1032
1033                         if(clip->lastsize[0]) {
1034                                 camera->sensor_x= tracking->camera.sensor_width;
1035                                 camera->sensor_y= tracking->camera.sensor_height;
1036
1037                                 camera->lens= focal*camera->sensor_x/(float)clip->lastsize[0];
1038                         }
1039
1040                         WM_event_add_notifier(C, NC_OBJECT, camera);
1041                 }
1042         }
1043
1044         DAG_id_tag_update(&clip->id, 0);
1045
1046         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
1047         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, NULL);
1048
1049         return OPERATOR_FINISHED;
1050 }
1051
1052 void CLIP_OT_solve_camera(wmOperatorType *ot)
1053 {
1054         /* identifiers */
1055         ot->name= "Solve Camera";
1056         ot->description= "Solve camera motion from tracks";
1057         ot->idname= "CLIP_OT_solve_camera";
1058
1059         /* api callbacks */
1060         ot->exec= solve_camera_exec;
1061         ot->poll= space_clip_tracking_poll;
1062
1063         /* flags */
1064         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1065 }
1066
1067 /********************** clear reconstruction operator *********************/
1068
1069 static int clear_reconstruction_exec(bContext *C, wmOperator *UNUSED(op))
1070 {
1071         SpaceClip *sc= CTX_wm_space_clip(C);
1072         MovieClip *clip= ED_space_clip(sc);
1073         MovieTracking *tracking= &clip->tracking;
1074         MovieTrackingTrack *track= tracking->tracks.first;
1075
1076         while(track) {
1077                 track->flag&= ~TRACK_HAS_BUNDLE;
1078
1079                 track= track->next;
1080         }
1081
1082         if(tracking->camera.reconstructed)
1083                 MEM_freeN(tracking->camera.reconstructed);
1084
1085         tracking->camera.reconstructed= NULL;
1086         tracking->camera.reconnr= 0;
1087
1088         DAG_id_tag_update(&clip->id, 0);
1089
1090         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
1091         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, NULL);
1092
1093         return OPERATOR_FINISHED;
1094 }
1095
1096 void CLIP_OT_clear_reconstruction(wmOperatorType *ot)
1097 {
1098         /* identifiers */
1099         ot->name= "Clear Reconstruciton";
1100         ot->description= "Clear all reconstruciton data";
1101         ot->idname= "CLIP_OT_clear_reconstruction";
1102
1103         /* api callbacks */
1104         ot->exec= clear_reconstruction_exec;
1105         ot->poll= space_clip_tracking_poll;
1106
1107         /* flags */
1108         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1109 }
1110
1111 /********************** clear track operator *********************/
1112
1113 static int clear_track_path_exec(bContext *C, wmOperator *op)
1114 {
1115         SpaceClip *sc= CTX_wm_space_clip(C);
1116         MovieClip *clip= ED_space_clip(sc);
1117         MovieTrackingTrack *track;
1118         int action= RNA_enum_get(op->ptr, "action");
1119
1120         track= clip->tracking.tracks.first;
1121         while(track) {
1122                 if(TRACK_SELECTED(track))
1123                         BKE_tracking_clear_path(track, sc->user.framenr, action);
1124
1125                 track= track->next;
1126         }
1127
1128         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
1129
1130         return OPERATOR_FINISHED;
1131 }
1132
1133 void CLIP_OT_clear_track_path(wmOperatorType *ot)
1134 {
1135         static EnumPropertyItem clear_path_actions[] = {
1136                         {TRACK_CLEAR_UPTO, "UPTO", 0, "Clear up-to", "Clear path up to current frame"},
1137                         {TRACK_CLEAR_REMAINED, "REMAINED", 0, "Clear remained", "Clear path at remained frames (after current)"},
1138                         {TRACK_CLEAR_ALL, "ALL", 0, "Clear all", "Clear the whole path"},
1139                         {0, NULL, 0, NULL, NULL}
1140         };
1141
1142         /* identifiers */
1143         ot->name= "Clear Track Path";
1144         ot->description= "Clear path of active track";
1145         ot->idname= "CLIP_OT_clear_track_path";
1146
1147         /* api callbacks */
1148         ot->exec= clear_track_path_exec;
1149         ot->poll= space_clip_tracking_poll;
1150
1151         /* flags */
1152         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1153
1154         /* proeprties */
1155         RNA_def_enum(ot->srna, "action", clear_path_actions, TRACK_CLEAR_REMAINED, "Action", "Clear action to execute");
1156
1157 }
1158
1159 /********************** disable markers operator *********************/
1160
1161 static int disable_markers_exec(bContext *C, wmOperator *op)
1162 {
1163         SpaceClip *sc= CTX_wm_space_clip(C);
1164         MovieClip *clip= ED_space_clip(sc);
1165         MovieTracking *tracking= &clip->tracking;
1166         MovieTrackingTrack *track= tracking->tracks.first;
1167         int action= RNA_enum_get(op->ptr, "action");
1168
1169         while(track) {
1170                 if(TRACK_VIEW_SELECTED(track)) {
1171                         MovieTrackingMarker *marker= BKE_tracking_ensure_marker(track, sc->user.framenr);
1172
1173                         if(action==0) marker->flag|= MARKER_DISABLED;
1174                         else if(action==1) marker->flag&= ~MARKER_DISABLED;
1175                         else marker->flag^= MARKER_DISABLED;
1176                 }
1177
1178                 track= track->next;
1179         }
1180
1181         DAG_id_tag_update(&clip->id, 0);
1182
1183         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
1184
1185         return OPERATOR_FINISHED;
1186 }
1187
1188 void CLIP_OT_disable_markers(wmOperatorType *ot)
1189 {
1190         static EnumPropertyItem actions_items[] = {
1191                         {0, "DISABLE", 0, "Disable", "Disable selected markers"},
1192                         {1, "ENABLE", 0, "Enable", "Enable selected markers"},
1193                         {2, "TOGGLE", 0, "Toggle", "Toggle disabled flag for selected markers"},
1194                         {0, NULL, 0, NULL, NULL}
1195         };
1196
1197         /* identifiers */
1198         ot->name= "Disable Markers";
1199         ot->description= "Disable/enable selected markers";
1200         ot->idname= "CLIP_OT_disable_markers";
1201
1202         /* api callbacks */
1203         ot->exec= disable_markers_exec;
1204         ot->poll= space_clip_tracking_poll;
1205
1206         /* flags */
1207         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1208
1209         /* properties */
1210         RNA_def_enum(ot->srna, "action", actions_items, 0, "Action", "Disable action to execute");
1211 }
1212
1213 /********************** set origin operator *********************/
1214
1215 static int count_selected_bundles(bContext *C)
1216 {
1217         SpaceClip *sc= CTX_wm_space_clip(C);
1218         MovieClip *clip= ED_space_clip(sc);
1219         MovieTrackingTrack *track;
1220         int tot= 0;
1221
1222         track= clip->tracking.tracks.first;
1223         while(track) {
1224                 if(TRACK_SELECTED(track))
1225                         tot++;
1226
1227                 track= track->next;
1228         }
1229
1230         return tot;
1231 }
1232
1233 static int set_origin_exec(bContext *C, wmOperator *op)
1234 {
1235         SpaceClip *sc= CTX_wm_space_clip(C);
1236         MovieClip *clip= ED_space_clip(sc);
1237         MovieTrackingTrack *track;
1238         Scene *scene= CTX_data_scene(C);
1239         Object *parent= scene->camera;
1240         float mat[4][4], vec[3];
1241
1242         if(count_selected_bundles(C)!=1) {
1243                 BKE_report(op->reports, RPT_ERROR, "Track with bundle should be selected to define origin position");
1244                 return OPERATOR_CANCELLED;
1245         }
1246
1247         if(scene->camera->parent)
1248                 parent= scene->camera->parent;
1249
1250         track= clip->tracking.tracks.first;
1251         while(track) {
1252                 if(TRACK_SELECTED(track))
1253                         break;
1254
1255                 track= track->next;
1256         }
1257
1258         BKE_get_tracking_mat(scene, mat);
1259         mul_v3_m4v3(vec, mat, track->bundle_pos);
1260
1261         sub_v3_v3(parent->loc, vec);
1262
1263         DAG_id_tag_update(&clip->id, 0);
1264         DAG_id_tag_update(&parent->id, OB_RECALC_OB);
1265
1266         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
1267         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, NULL);
1268
1269         return OPERATOR_FINISHED;
1270 }
1271
1272 void CLIP_OT_set_origin(wmOperatorType *ot)
1273 {
1274         /* identifiers */
1275         ot->name= "Set Origin";
1276         ot->description= "Set active marker as origin";
1277         ot->idname= "CLIP_OT_set_origin";
1278
1279         /* api callbacks */
1280         ot->exec= set_origin_exec;
1281         ot->poll= space_clip_frame_camera_poll;
1282
1283         /* flags */
1284         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1285 }
1286
1287 /********************** set floor operator *********************/
1288
1289 static void set_axis(Scene *scene,  Object *ob, MovieTrackingTrack *track, char axis)
1290 {
1291         float mat[4][4], vec[3], obmat[4][4];
1292
1293         BKE_get_tracking_mat(scene, mat);
1294         mul_v3_m4v3(vec, mat, track->bundle_pos);
1295
1296         if(len_v2(vec)<1e-3)
1297                 return;
1298
1299         unit_m4(mat);
1300
1301         if(axis=='X') {
1302                 if(fabsf(vec[1])<1e-3) {
1303                         mat[0][0]= -1.f; mat[0][1]= 0.f; mat[0][2]= 0.f;
1304                         mat[1][0]= 0.f; mat[1][1]= -1.f; mat[1][2]= 0.f;
1305                         mat[2][0]= 0.f; mat[2][1]= 0.f; mat[2][2]= 1.0f;
1306                 } else {
1307                         copy_v3_v3(mat[0], vec);
1308                         mat[0][2]= 0.f;
1309                         mat[2][0]= 0.f; mat[2][1]= 0.f; mat[2][2]= 1.0f;
1310                         cross_v3_v3v3(mat[1], mat[2], mat[0]);
1311                 }
1312         } else {
1313                 if(fabsf(vec[0])<1e-3) {
1314                         mat[0][0]= -1.f; mat[0][1]= 0.f; mat[0][2]= 0.f;
1315                         mat[1][0]= 0.f; mat[1][1]= -1.f; mat[1][2]= 0.f;
1316                         mat[2][0]= 0.f; mat[2][1]= 0.f; mat[2][2]= 1.0f;
1317                 } else {
1318                         copy_v3_v3(mat[1], vec);
1319                         mat[1][2]= 0.f;
1320                         mat[2][0]= 0.f; mat[2][1]= 0.f; mat[2][2]= 1.0f;
1321                         cross_v3_v3v3(mat[0], mat[1], mat[2]);
1322                 }
1323         }
1324
1325         normalize_v3(mat[0]);
1326         normalize_v3(mat[1]);
1327         normalize_v3(mat[2]);
1328
1329         invert_m4(mat);
1330
1331         object_to_mat4(ob, obmat);
1332         mul_m4_m4m4(mat, obmat, mat);
1333         object_apply_mat4(ob, mat, 0, 0);
1334 }
1335
1336 static int set_floor_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         MovieTrackingTrack *track, *sel, *axis_track= NULL;
1342         Object *camera= scene->camera;
1343         Object *parent= camera;
1344         int tot= 0, sel_type;
1345         float vec[3][3], mat[4][4], obmat[4][4], newmat[4][4], orig[3]= {0.f, 0.f, 0.f};
1346         float rot[4][4]={{0.f, 0.f, -1.f, 0.f},
1347                          {0.f, 1.f, 0.f, 0.f},
1348                          {1.f, 0.f, 0.f, 0.f},
1349                          {0.f, 0.f, 0.f, 1.f}}; /* 90 degrees Y-axis rotation matrix */
1350
1351         if(count_selected_bundles(C)!=3) {
1352                 BKE_report(op->reports, RPT_ERROR, "Three tracks with bundles are needed to orient the floor");
1353                 return OPERATOR_CANCELLED;
1354         }
1355
1356         if(scene->camera->parent)
1357                 parent= scene->camera->parent;
1358
1359         BKE_get_tracking_mat(scene, mat);
1360
1361         BKE_movieclip_last_selection(clip, &sel_type, (void**)&sel);
1362
1363         /* get 3 bundles to use as reference */
1364         track= clip->tracking.tracks.first;
1365         while(track && tot<3) {
1366                 if(track->flag&TRACK_HAS_BUNDLE && TRACK_SELECTED(track)) {
1367                         mul_v3_m4v3(vec[tot], mat, track->bundle_pos);
1368
1369                         if(tot==0 || (sel_type==MCLIP_SEL_TRACK && track==sel))
1370                                 copy_v3_v3(orig, vec[tot]);
1371                         else
1372                                 axis_track= track;
1373
1374                         tot++;
1375                 }
1376
1377                 track= track->next;
1378         }
1379
1380         sub_v3_v3(vec[1], vec[0]);
1381         sub_v3_v3(vec[2], vec[0]);
1382
1383         /* construct ortho-normal basis */
1384         unit_m4(mat);
1385
1386         cross_v3_v3v3(mat[0], vec[1], vec[2]);
1387         copy_v3_v3(mat[1], vec[1]);
1388         cross_v3_v3v3(mat[2], mat[0], mat[1]);
1389
1390         normalize_v3(mat[0]);
1391         normalize_v3(mat[1]);
1392         normalize_v3(mat[2]);
1393
1394         /* move to origin point */
1395         mat[3][0]= orig[0];
1396         mat[3][1]= orig[1];
1397         mat[3][2]= orig[2];
1398
1399         invert_m4(mat);
1400
1401         object_to_mat4(parent, obmat);
1402         mul_m4_m4m4(mat, obmat, mat);
1403         mul_m4_m4m4(newmat, mat, rot);
1404         object_apply_mat4(parent, newmat, 0, 0);
1405
1406         /* make camera have positive z-coordinate */
1407         mul_v3_m4v3(vec[0], mat, camera->loc);
1408         if(camera->loc[2]<0) {
1409                 invert_m4(rot);
1410                 mul_m4_m4m4(newmat, mat, rot);
1411                 object_apply_mat4(camera, newmat, 0, 0);
1412         }
1413
1414         where_is_object(scene, parent);
1415         set_axis(scene, parent, axis_track, 'X');
1416
1417         DAG_id_tag_update(&clip->id, 0);
1418         DAG_id_tag_update(&parent->id, OB_RECALC_OB);
1419
1420         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
1421         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, NULL);
1422
1423         return OPERATOR_FINISHED;
1424 }
1425
1426 void CLIP_OT_set_floor(wmOperatorType *ot)
1427 {
1428         /* identifiers */
1429         ot->name= "Set Floor";
1430         ot->description= "Set floor using 3 selected bundles";
1431         ot->idname= "CLIP_OT_set_floor";
1432
1433         /* api callbacks */
1434         ot->exec= set_floor_exec;
1435         ot->poll= space_clip_camera_poll;
1436
1437         /* flags */
1438         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1439 }
1440
1441 /********************** set origin operator *********************/
1442
1443 static int set_axis_exec(bContext *C, wmOperator *op)
1444 {
1445         SpaceClip *sc= CTX_wm_space_clip(C);
1446         MovieClip *clip= ED_space_clip(sc);
1447         MovieTrackingTrack *track;
1448         Scene *scene= CTX_data_scene(C);
1449         Object *parent= scene->camera;
1450         int axis= RNA_enum_get(op->ptr, "axis");
1451
1452         if(count_selected_bundles(C)!=1) {
1453                 BKE_report(op->reports, RPT_ERROR, "Track with bundle should be selected to define X-axis");
1454
1455                 return OPERATOR_CANCELLED;
1456         }
1457
1458         if(scene->camera->parent)
1459                 parent= scene->camera->parent;
1460
1461         track= clip->tracking.tracks.first;
1462         while(track) {
1463                 if(TRACK_SELECTED(track))
1464                         break;
1465
1466                 track= track->next;
1467         }
1468
1469         set_axis(scene, parent, track, axis==0?'X':'Y');
1470
1471         DAG_id_tag_update(&clip->id, 0);
1472         DAG_id_tag_update(&parent->id, OB_RECALC_OB);
1473
1474         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
1475         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, NULL);
1476
1477         return OPERATOR_FINISHED;
1478 }
1479
1480 void CLIP_OT_set_axis(wmOperatorType *ot)
1481 {
1482         static EnumPropertyItem axis_actions[] = {
1483                         {0, "X", 0, "X", "Align bundle align X axis"},
1484                         {1, "Y", 0, "Y", "Align bundle align Y axis"},
1485                         {0, NULL, 0, NULL, NULL}
1486         };
1487
1488         /* identifiers */
1489         ot->name= "Set Axis";
1490         ot->description= "Set direction of scene axis";
1491         ot->idname= "CLIP_OT_set_axis";
1492
1493         /* api callbacks */
1494         ot->exec= set_axis_exec;
1495         ot->poll= space_clip_frame_camera_poll;
1496
1497         /* flags */
1498         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1499
1500         /* properties */
1501         RNA_def_enum(ot->srna, "axis", axis_actions, 0, "Axis", "Axis to use to align bundle along");
1502 }
1503
1504 /********************** set scale operator *********************/
1505
1506 static int set_scale_exec(bContext *C, wmOperator *op)
1507 {
1508         SpaceClip *sc= CTX_wm_space_clip(C);
1509         MovieClip *clip= ED_space_clip(sc);
1510         MovieTrackingTrack *track;
1511         Scene *scene= CTX_data_scene(C);
1512         Object *parent= scene->camera;
1513         int tot= 0;
1514         float vec[2][3], mat[4][4], scale;
1515
1516         if(count_selected_bundles(C)!=2) {
1517                 BKE_report(op->reports, RPT_ERROR, "Two tracks with bundles should be selected to scale scene");
1518
1519                 return OPERATOR_CANCELLED;
1520         }
1521
1522         if(scene->camera->parent)
1523                 parent= scene->camera->parent;
1524
1525         BKE_get_tracking_mat(scene, mat);
1526
1527         track= clip->tracking.tracks.first;
1528         while(track) {
1529                 if(TRACK_SELECTED(track)) {
1530                         mul_v3_m4v3(vec[tot], mat, track->bundle_pos);
1531                         tot++;
1532                 }
1533
1534                 track= track->next;
1535         }
1536
1537         sub_v3_v3(vec[0], vec[1]);
1538
1539         if(len_v3(vec[0])>1e-5) {
1540                 scale= clip->tracking.settings.dist / len_v3(vec[0]);
1541
1542                 mul_v3_fl(parent->size, scale);
1543                 mul_v3_fl(parent->loc, scale);
1544
1545                 DAG_id_tag_update(&clip->id, 0);
1546                 DAG_id_tag_update(&parent->id, OB_RECALC_OB);
1547
1548                 WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
1549                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, NULL);
1550         }
1551
1552         return OPERATOR_FINISHED;
1553 }
1554
1555 void CLIP_OT_set_scale(wmOperatorType *ot)
1556 {
1557         /* identifiers */
1558         ot->name= "Set Scale";
1559         ot->description= "Set scale of scene";
1560         ot->idname= "CLIP_OT_set_scale";
1561
1562         /* api callbacks */
1563         ot->exec= set_scale_exec;
1564         ot->poll= space_clip_frame_camera_poll;
1565
1566         /* flags */
1567         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1568 }
1569
1570 /********************** set principal center operator *********************/
1571
1572 static int set_center_principal_exec(bContext *C, wmOperator *UNUSED(op))
1573 {
1574         SpaceClip *sc= CTX_wm_space_clip(C);
1575         MovieClip *clip= ED_space_clip(sc);
1576         int width, height;
1577
1578         BKE_movieclip_acquire_size(clip, &sc->user, &width, &height);
1579
1580         if(width==0 || height==0)
1581                 return OPERATOR_CANCELLED;
1582
1583         clip->tracking.camera.principal[0]= ((float)width)/2.0f;
1584         clip->tracking.camera.principal[1]= ((float)height)/2.0f;
1585
1586         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, clip);
1587
1588         return OPERATOR_FINISHED;
1589 }
1590
1591 void CLIP_OT_set_center_principal(wmOperatorType *ot)
1592 {
1593         /* identifiers */
1594         ot->name= "Set Principal to Center";
1595         ot->description= "Set principal point to center of footage";
1596         ot->idname= "CLIP_OT_set_center_principal";
1597
1598         /* api callbacks */
1599         ot->exec= set_center_principal_exec;
1600         ot->poll= space_clip_tracking_poll;
1601
1602         /* flags */
1603         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1604 }
1605 /********************** slide marker opertaotr *********************/
1606
1607 typedef struct {
1608         int area;
1609         MovieTrackingTrack *track;
1610
1611         int mval[2];
1612         int width, height;
1613         float *min, *max, *pos;
1614         float smin[2], smax[2], spos[2];
1615
1616         int lock, accurate;
1617 } SlideMarkerData;
1618
1619 static SlideMarkerData *create_slide_marker_data(MovieTrackingTrack *track, MovieTrackingMarker *marker, wmEvent *event, int area, int width, int height)
1620 {
1621         SlideMarkerData *data= MEM_callocN(sizeof(SlideMarkerData), "slide marker data");
1622
1623         data->area= area;
1624         data->track= track;
1625
1626         if(area==TRACK_AREA_POINT) {
1627                 data->pos= marker->pos;
1628                 copy_v2_v2(data->spos, marker->pos);
1629         } else if(area==TRACK_AREA_PAT) {
1630                 data->min= track->pat_min;
1631                 data->max= track->pat_max;
1632         } else if(area==TRACK_AREA_SEARCH) {
1633                 data->min= track->search_min;
1634                 data->max= track->search_max;
1635         }
1636
1637         if(ELEM(area, TRACK_AREA_PAT, TRACK_AREA_SEARCH)) {
1638                 copy_v2_v2(data->smin, data->min);
1639                 copy_v2_v2(data->smax, data->max);
1640         }
1641
1642         data->mval[0]= event->mval[0];
1643         data->mval[1]= event->mval[1];
1644
1645         data->width= width;
1646         data->height= height;
1647
1648         data->lock= 1;
1649
1650         return data;
1651 }
1652
1653 /* corner = 0: right-bottom corner,
1654    corner = 1: left-top corner */
1655 static int mouse_on_corner(SpaceClip *sc, MovieTrackingTrack *track, float size, float co[2], int corner,
1656                         float *pos, float *min, float *max, int width, int height)
1657 {
1658         int inside= 0;
1659         float nco[2], crn[2], dx, dy;
1660
1661         nco[0]= co[0]/width;
1662         nco[1]= co[1]/height;
1663
1664         dx= size/width/sc->zoom;
1665         dy= size/height/sc->zoom;
1666
1667         dx=MIN2(dx, (track->search_max[0]-track->search_min[0])/5);
1668         dy=MIN2(dy, (track->search_max[1]-track->search_min[1])/5);
1669
1670         if(corner==0) {
1671                 crn[0]= pos[0]+max[0];
1672                 crn[1]= pos[1]+min[1];
1673
1674                 inside= nco[0]>=crn[0]-dx && nco[0]<=crn[0] && nco[1]>=crn[1] && nco[1]<=crn[1]+dy;
1675         } else {
1676                 crn[0]= pos[0]+min[0];
1677                 crn[1]= pos[1]+max[1];
1678
1679                 inside= nco[0]>=crn[0] && nco[0]<=crn[0]+dx && nco[1]>=crn[1]-dy && nco[1]<=crn[1];
1680         }
1681
1682         return inside;
1683 }
1684
1685 static int slide_marker_invoke(bContext *C, wmOperator *op, wmEvent *event)
1686 {
1687         SpaceClip *sc= CTX_wm_space_clip(C);
1688         MovieClip *clip= ED_space_clip(sc);
1689         MovieTrackingTrack *track;
1690         int width, height;
1691         float co[2];
1692
1693         ED_space_clip_size(sc, &width, &height);
1694
1695         if(width==0 || height==0)
1696                 return OPERATOR_PASS_THROUGH;
1697
1698         mouse_pos(C, event, co);
1699
1700         track= clip->tracking.tracks.first;
1701         while(track) {
1702                 if(TRACK_VIEW_SELECTED(track)) {
1703                         MovieTrackingMarker *marker= BKE_tracking_get_marker(track, sc->user.framenr);
1704
1705                         if(marker && (marker->flag&MARKER_DISABLED)==0) {
1706                                 if(sc->flag&SC_SHOW_MARKER_SEARCH) {
1707                                         if(mouse_on_corner(sc, track, 15.0f, co, 1, marker->pos, track->search_min, track->search_max, width, height))
1708                                                 op->customdata= create_slide_marker_data(track, marker, event, TRACK_AREA_POINT, width, height);
1709
1710                                         if(mouse_on_corner(sc, track, 15.0f, co, 0, marker->pos, track->search_min, track->search_max, width, height))
1711                                                 op->customdata= create_slide_marker_data(track, marker, event, TRACK_AREA_SEARCH, width, height);
1712                                 }
1713
1714                                 if(sc->flag&SC_SHOW_MARKER_PATTERN)
1715                                         if(mouse_on_corner(sc, track, 10.0f, co, 0, marker->pos, track->pat_min, track->pat_max, width, height))
1716                                                 op->customdata= create_slide_marker_data(track, marker, event, TRACK_AREA_PAT, width, height);
1717
1718                                 if(op->customdata) {
1719                                         WM_event_add_modal_handler(C, op);
1720
1721                                         return OPERATOR_RUNNING_MODAL;
1722                                 }
1723                         }
1724                 }
1725
1726                 track= track->next;
1727         }
1728
1729         return OPERATOR_CANCELLED;
1730 }
1731
1732 static int slide_marker_modal(bContext *C, wmOperator *op, wmEvent *event)
1733 {
1734         SpaceClip *sc= CTX_wm_space_clip(C);
1735         SlideMarkerData *data= (SlideMarkerData *)op->customdata;
1736         float dx, dy, mdelta[2];
1737
1738         switch(event->type) {
1739                 case LEFTCTRLKEY:
1740                 case RIGHTCTRLKEY:
1741                 case LEFTSHIFTKEY:
1742                 case RIGHTSHIFTKEY:
1743                         if(data->area != TRACK_AREA_POINT)
1744                                 if(ELEM(event->type, LEFTCTRLKEY, RIGHTCTRLKEY))
1745                                         data->lock= event->val==KM_RELEASE;
1746
1747                         if(ELEM(event->type, LEFTSHIFTKEY, RIGHTSHIFTKEY))
1748                                 data->accurate= event->val==KM_PRESS;
1749
1750                         /* no break! update area size */
1751
1752                 case MOUSEMOVE:
1753                         mdelta[0]= event->mval[0]-data->mval[0];
1754                         mdelta[1]= event->mval[1]-data->mval[1];
1755
1756                         dx= mdelta[0]/data->width/sc->zoom;
1757                         dy= mdelta[1]/data->height/sc->zoom;
1758
1759                         if(data->accurate) {
1760                                 dx/= 5;
1761                                 dy/= 5;
1762                         }
1763
1764                         if(data->area == TRACK_AREA_POINT) {
1765                                 data->pos[0]= data->spos[0]+dx;
1766                                 data->pos[1]= data->spos[1]+dy;
1767                         } else {
1768                                 data->min[0]= data->smin[0]-dx;
1769                                 data->max[0]= data->smax[0]+dx;
1770
1771                                 data->min[1]= data->smin[1]+dy;
1772                                 data->max[1]= data->smax[1]-dy;
1773
1774                                 if(data->lock) {
1775                                         float h= (data->max[0]-data->min[0])*data->width/data->height;
1776
1777                                         data->min[1]= data->spos[1]-h/2;
1778                                         data->max[1]= data->spos[1]+h/2;
1779                                 }
1780
1781
1782                                 if(data->area==TRACK_AREA_SEARCH) BKE_tracking_clamp_track(data->track, CLAMP_SEARCH_DIM);
1783                                 else BKE_tracking_clamp_track(data->track, CLAMP_PAT_DIM);
1784                         }
1785
1786                         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, NULL);
1787
1788                         break;
1789
1790                 case LEFTMOUSE:
1791                         if(event->val==KM_RELEASE) {
1792                                 MEM_freeN(op->customdata);
1793
1794                                 return OPERATOR_FINISHED;
1795                         }
1796
1797                         break;
1798
1799                 case ESCKEY:
1800                         /* cancel sliding */
1801                         if(data->area == TRACK_AREA_POINT) {
1802                                 data->pos[0]= data->spos[0];
1803                                 data->pos[1]= data->spos[1];
1804                         } else {
1805                                 data->min[0]= data->smin[0];
1806                                 data->max[0]= data->smax[0];
1807
1808                                 data->min[1]= data->smin[1];
1809                                 data->max[1]= data->smax[1];
1810                         }
1811
1812                         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, NULL);
1813
1814                         return OPERATOR_CANCELLED;
1815         }
1816
1817         return OPERATOR_PASS_THROUGH;
1818 }
1819
1820 void CLIP_OT_slide_marker(wmOperatorType *ot)
1821 {
1822         /* identifiers */
1823         ot->name= "Slide Marker";
1824         ot->description= "Slide marker areas";
1825         ot->idname= "CLIP_OT_slide_marker";
1826
1827         /* api callbacks */
1828         //ot->exec= slide_marker_exec;
1829         ot->poll= space_clip_frame_poll;
1830         ot->invoke= slide_marker_invoke;
1831         ot->modal= slide_marker_modal;
1832
1833         /* flags */
1834         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1835
1836         /* properties */
1837         RNA_def_float_vector(ot->srna, "offset", 2, NULL, -FLT_MAX, FLT_MAX,
1838                 "Offset", "Offset in floating point units, 1.0 is the width and height of the image.", -FLT_MAX, FLT_MAX);
1839 }
1840
1841 /********************** hide tracks opertaotr *********************/
1842
1843 static int hide_tracks_exec(bContext *C, wmOperator *op)
1844 {
1845         SpaceClip *sc= CTX_wm_space_clip(C);
1846         MovieClip *clip= ED_space_clip(sc);
1847         MovieTrackingTrack *track;
1848         int sel_type, unselected;
1849         void *sel;
1850
1851         unselected= RNA_boolean_get(op->ptr, "unselected");
1852
1853         BKE_movieclip_last_selection(clip, &sel_type, &sel);
1854
1855         track= clip->tracking.tracks.first;
1856         while(track) {
1857                 if(unselected==0 && TRACK_SELECTED(track)) {
1858                         track->flag|= TRACK_HIDDEN;
1859                 } else if(unselected==1 && !TRACK_SELECTED(track)) {
1860                         track->flag|= TRACK_HIDDEN;
1861                 }
1862
1863                 track= track->next;
1864         }
1865
1866         if(sel_type==MCLIP_SEL_TRACK) {
1867                 track= (MovieTrackingTrack *)sel;
1868
1869                 if(!TRACK_VISIBLE(track))
1870                         BKE_movieclip_set_selection(clip, MCLIP_SEL_NONE, NULL);
1871         }
1872
1873         WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, NULL);
1874
1875         return OPERATOR_FINISHED;
1876 }
1877
1878 void CLIP_OT_hide_tracks(wmOperatorType *ot)
1879 {
1880         /* identifiers */
1881         ot->name= "Hide Tracks";
1882         ot->description= "Hide selected tracks";
1883         ot->idname= "CLIP_OT_hide_tracks";
1884
1885         /* api callbacks */
1886         ot->exec= hide_tracks_exec;
1887         ot->poll= space_clip_tracking_poll;
1888
1889         /* flags */
1890         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1891
1892         /* properties */
1893         RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected tracks");
1894 }
1895
1896 /********************** hide tracks clear opertaotr *********************/
1897
1898 static int hide_tracks_clear_exec(bContext *C, wmOperator *UNUSED(op))
1899 {
1900         SpaceClip *sc= CTX_wm_space_clip(C);
1901         MovieClip *clip= ED_space_clip(sc);
1902         MovieTrackingTrack *track;
1903
1904         track= clip->tracking.tracks.first;
1905         while(track) {
1906                 track->flag&= ~TRACK_HIDDEN;
1907
1908                 track= track->next;
1909         }
1910
1911         WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, NULL);
1912
1913         return OPERATOR_FINISHED;
1914 }
1915
1916 void CLIP_OT_hide_tracks_clear(wmOperatorType *ot)
1917 {
1918         /* identifiers */
1919         ot->name= "Hide Tracks Clear";
1920         ot->description= "Clear hide selected tracks";
1921         ot->idname= "CLIP_OT_hide_tracks_clear";
1922
1923         /* api callbacks */
1924         ot->exec= hide_tracks_clear_exec;
1925         ot->poll= space_clip_tracking_poll;
1926
1927         /* flags */
1928         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1929 }
1930
1931 /********************** detect features opertaotr *********************/
1932
1933 static int detect_features_exec(bContext *C, wmOperator *UNUSED(op))
1934 {
1935         SpaceClip *sc= CTX_wm_space_clip(C);
1936         MovieClip *clip= ED_space_clip(sc);
1937         ImBuf *ibuf= BKE_movieclip_acquire_ibuf(clip, &sc->user);
1938         MovieTrackingTrack *track= clip->tracking.tracks.first;
1939
1940         /* deselect existing tracks */
1941         while(track) {
1942                 track->flag&= ~SELECT;
1943                 track->pat_flag&= ~SELECT;
1944                 track->search_flag&= ~SELECT;
1945
1946                 track= track->next;
1947         }
1948
1949         BKE_tracking_detect(&clip->tracking, ibuf, sc->user.framenr);
1950
1951         IMB_freeImBuf(ibuf);
1952
1953         BKE_movieclip_set_selection(clip, MCLIP_SEL_NONE, NULL);
1954         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, NULL);
1955
1956         return OPERATOR_FINISHED;
1957 }
1958
1959 void CLIP_OT_detect_features(wmOperatorType *ot)
1960 {
1961         /* identifiers */
1962         ot->name= "Detect Features";
1963         ot->description= "Automatically detect features to track";
1964         ot->idname= "CLIP_OT_detect_features";
1965
1966         /* api callbacks */
1967         ot->exec= detect_features_exec;
1968         ot->poll= space_clip_frame_poll;
1969
1970         /* flags */
1971         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1972 }