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