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