svn merge ^/trunk/blender -r43220:43278 --accept postpone
[blender-staging.git] / source / blender / editors / space_clip / tracking_ops.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2011 Blender Foundation.
19  * All rights reserved.
20  *
21  *
22  * Contributor(s): Blender Foundation,
23  *                 Sergey Sharybin
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/space_clip/tracking_ops.c
29  *  \ingroup spclip
30  */
31
32 #include "MEM_guardedalloc.h"
33
34 #include "DNA_camera_types.h"
35 #include "DNA_constraint_types.h"
36 #include "DNA_gpencil_types.h"
37 #include "DNA_movieclip_types.h"
38 #include "DNA_object_types.h"   /* SELECT */
39 #include "DNA_scene_types.h"
40
41 #include "BLI_utildefines.h"
42 #include "BLI_math.h"
43 #include "BLI_listbase.h"
44 #include "BLI_rect.h"
45 #include "BLI_blenlib.h"
46
47 #include "BKE_main.h"
48 #include "BKE_context.h"
49 #include "BKE_constraint.h"
50 #include "BKE_movieclip.h"
51 #include "BKE_tracking.h"
52 #include "BKE_global.h"
53 #include "BKE_depsgraph.h"
54 #include "BKE_object.h"
55 #include "BKE_report.h"
56 #include "BKE_scene.h"
57 #include "BKE_library.h"
58 #include "BKE_sound.h"
59
60 #include "WM_api.h"
61 #include "WM_types.h"
62
63 #include "ED_screen.h"
64 #include "ED_clip.h"
65 #include "ED_keyframing.h"
66
67 #include "IMB_imbuf_types.h"
68 #include "IMB_imbuf.h"
69
70 #include "UI_interface.h"
71
72 #include "RNA_access.h"
73 #include "RNA_define.h"
74
75 #include "PIL_time.h"
76
77 #include "UI_view2d.h"
78
79 #include "clip_intern.h"        // own include
80
81 static int space_clip_frame_poll(bContext *C)
82 {
83         SpaceClip *sc= CTX_wm_space_clip(C);
84
85         if(sc) {
86                 MovieClip *clip= ED_space_clip(sc);
87
88                 if(clip)
89                         return BKE_movieclip_has_frame(clip, &sc->user);
90         }
91
92         return 0;
93 }
94
95 /********************** add marker operator *********************/
96
97 static void add_marker(SpaceClip *sc, float x, float y)
98 {
99         MovieClip *clip= ED_space_clip(sc);
100         MovieTracking *tracking= &clip->tracking;
101         ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
102         MovieTrackingTrack *track;
103         int width, height;
104         
105         ED_space_clip_size(sc, &width, &height);
106
107         track= BKE_tracking_add_track(tracking, tracksbase, x, y, sc->user.framenr, width, height);
108
109         BKE_tracking_select_track(tracksbase, track, TRACK_AREA_ALL, 0);
110
111         clip->tracking.act_track= track;
112 }
113
114 static int add_marker_exec(bContext *C, wmOperator *op)
115 {
116         SpaceClip *sc= CTX_wm_space_clip(C);
117         MovieClip *clip= ED_space_clip(sc);
118         float pos[2];
119         int width, height;
120
121         ED_space_clip_size(sc, &width, &height);
122         if(!width || !height)
123                 return OPERATOR_CANCELLED;
124
125         RNA_float_get_array(op->ptr, "location", pos);
126
127         add_marker(sc, pos[0], pos[1]);
128
129         /* reset offset from locked position, so frame jumping wouldn't be so confusing */
130         sc->xlockof= 0;
131         sc->ylockof= 0;
132
133         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, clip);
134
135         return OPERATOR_FINISHED;
136 }
137
138 static int add_marker_invoke(bContext *C, wmOperator *op, wmEvent *event)
139 {
140         float co[2];
141
142         ED_clip_mouse_pos(C, event, co);
143
144         RNA_float_set_array(op->ptr, "location", co);
145
146         return add_marker_exec(C, op);
147 }
148
149 void CLIP_OT_add_marker(wmOperatorType *ot)
150 {
151         /* identifiers */
152         ot->name= "Add Marker";
153         ot->idname= "CLIP_OT_add_marker";
154         ot->description= "Place new marker at specified location";
155
156         /* api callbacks */
157         ot->invoke= add_marker_invoke;
158         ot->exec= add_marker_exec;
159         ot->poll= space_clip_frame_poll;
160
161         /* flags */
162         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
163
164         /* properties */
165         RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MIN, FLT_MAX,
166                 "Location", "Location of marker on frame", -1.0f, 1.0f);
167 }
168
169 /********************** delete track operator *********************/
170
171 static int delete_track_exec(bContext *C, wmOperator *UNUSED(op))
172 {
173         SpaceClip *sc= CTX_wm_space_clip(C);
174         MovieClip *clip= ED_space_clip(sc);
175         MovieTracking *tracking= &clip->tracking;
176         ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
177         MovieTrackingTrack *track= tracksbase->first, *next;
178
179         while(track) {
180                 next= track->next;
181
182                 if(TRACK_VIEW_SELECTED(sc, track))
183                         clip_delete_track(C, clip, tracksbase, track);
184
185                 track= next;
186         }
187
188         /* nothing selected now, unlock view so it can be scrolled nice again */
189         sc->flag&= ~SC_LOCK_SELECTION;
190
191         return OPERATOR_FINISHED;
192 }
193
194 void CLIP_OT_delete_track(wmOperatorType *ot)
195 {
196         /* identifiers */
197         ot->name= "Delete Track";
198         ot->idname= "CLIP_OT_delete_track";
199         ot->description= "Delete selected tracks";
200
201         /* api callbacks */
202         ot->invoke= WM_operator_confirm;
203         ot->exec= delete_track_exec;
204         ot->poll= ED_space_clip_poll;
205
206         /* flags */
207         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
208 }
209
210 /********************** delete marker operator *********************/
211
212 static int delete_marker_exec(bContext *C, wmOperator *UNUSED(op))
213 {
214         SpaceClip *sc= CTX_wm_space_clip(C);
215         MovieClip *clip= ED_space_clip(sc);
216         ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
217         MovieTrackingTrack *track= tracksbase->first, *next;
218         int framenr= sc->user.framenr;
219         int has_selection= 0;
220
221         while(track) {
222                 next= track->next;
223
224                 if(TRACK_VIEW_SELECTED(sc, track)) {
225                         MovieTrackingMarker *marker= BKE_tracking_exact_marker(track, framenr);
226
227                         if(marker) {
228                                 has_selection|= track->markersnr>1;
229
230                                 clip_delete_marker(C, clip, tracksbase, track, marker);
231                         }
232                 }
233
234                 track= next;
235         }
236
237         if(!has_selection) {
238                 /* nothing selected now, unlock view so it can be scrolled nice again */
239                 sc->flag&= ~SC_LOCK_SELECTION;
240         }
241
242         return OPERATOR_FINISHED;
243 }
244
245 void CLIP_OT_delete_marker(wmOperatorType *ot)
246 {
247         /* identifiers */
248         ot->name= "Delete Marker";
249         ot->idname= "CLIP_OT_delete_marker";
250         ot->description= "Delete marker for current frame from selected tracks";
251
252         /* api callbacks */
253         ot->invoke= WM_operator_confirm;
254         ot->exec= delete_marker_exec;
255         ot->poll= ED_space_clip_poll;
256
257         /* flags */
258         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
259 }
260
261 /********************** slide marker operator *********************/
262
263 #define SLIDE_ACTION_POS        0
264 #define SLIDE_ACTION_SIZE       1
265 #define SLIDE_ACTION_OFFSET     2
266
267 typedef struct {
268         int area, action;
269         MovieTrackingTrack *track;
270         MovieTrackingMarker *marker;
271
272         int mval[2];
273         int width, height;
274         float *min, *max, *pos, *offset;
275         float smin[2], smax[2], spos[2], soff[2];
276         float (*smarkers)[2];
277
278         int lock, accurate;
279 } SlideMarkerData;
280
281 static SlideMarkerData *create_slide_marker_data(SpaceClip *sc, MovieTrackingTrack *track,
282                         MovieTrackingMarker *marker, wmEvent *event, int area, int action, int width, int height)
283 {
284         SlideMarkerData *data= MEM_callocN(sizeof(SlideMarkerData), "slide marker data");
285
286         marker= BKE_tracking_ensure_marker(track, sc->user.framenr);
287
288         data->area= area;
289         data->action= action;
290         data->track= track;
291         data->marker= marker;
292
293         if(area==TRACK_AREA_POINT) {
294                 data->pos= marker->pos;
295                 data->offset= track->offset;
296                 copy_v2_v2(data->spos, marker->pos);
297                 copy_v2_v2(data->soff, track->offset);
298         } else if(area==TRACK_AREA_PAT) {
299                 if(action==SLIDE_ACTION_SIZE) {
300                         data->min= track->pat_min;
301                         data->max= track->pat_max;
302                 } else {
303                         int a;
304
305                         data->pos= marker->pos;
306                         data->offset= track->offset;
307
308                         copy_v2_v2(data->soff, track->offset);
309
310                         data->smarkers= MEM_callocN(sizeof(*data->smarkers)*track->markersnr, "slide marekrs");
311                         for(a= 0; a<track->markersnr; a++)
312                                 copy_v2_v2(data->smarkers[a], track->markers[a].pos);
313                 }
314         } else if(area==TRACK_AREA_SEARCH) {
315                 data->min= track->search_min;
316                 data->max= track->search_max;
317         }
318
319         if(area==TRACK_AREA_SEARCH || (area==TRACK_AREA_PAT && action!=SLIDE_ACTION_OFFSET)) {
320                 copy_v2_v2(data->smin, data->min);
321                 copy_v2_v2(data->smax, data->max);
322         }
323
324         data->mval[0]= event->mval[0];
325         data->mval[1]= event->mval[1];
326
327         data->width= width;
328         data->height= height;
329
330         if(action==SLIDE_ACTION_SIZE)
331                 data->lock= 1;
332
333         return data;
334 }
335
336 /* corner = 0: right-bottom corner,
337    corner = 1: left-top corner */
338 static int mouse_on_corner(SpaceClip *sc, MovieTrackingTrack *track, MovieTrackingMarker *marker,
339                         int area, float co[2], int corner, int width, int height)
340 {
341         int inside= 0;
342         float size= 12.0f;
343         float min[2], max[2];
344         float crn[2], dx, dy, tdx, tdy;
345
346         if(area==TRACK_AREA_SEARCH) {
347                 copy_v2_v2(min, track->search_min);
348                 copy_v2_v2(max, track->search_max);
349         } else {
350                 copy_v2_v2(min, track->pat_min);
351                 copy_v2_v2(max, track->pat_max);
352         }
353
354         dx= size/width/sc->zoom;
355         dy= size/height/sc->zoom;
356
357         tdx= 5.0f/width/sc->zoom;
358         tdy= 5.0f/height/sc->zoom;
359
360         dx= MIN2(dx, (max[0]-min[0])/6.0f) + tdx;
361         dy= MIN2(dy, (max[1]-min[1])/6.0f) + tdy;
362
363         if(corner==0) {
364                 crn[0]= marker->pos[0]+max[0];
365                 crn[1]= marker->pos[1]+min[1];
366
367                 inside= co[0]>=crn[0]-dx && co[0]<=crn[0]+tdx && co[1]>=crn[1]-tdy && co[1]<=crn[1]+dy;
368         } else {
369                 crn[0]= marker->pos[0]+min[0];
370                 crn[1]= marker->pos[1]+max[1];
371
372                 inside= co[0]>=crn[0]-dx && co[0]<=crn[0]+dx && co[1]>=crn[1]-dy && co[1]<=crn[1]+dy;
373         }
374
375         return inside;
376 }
377
378 static int mouse_on_offset(SpaceClip *sc, MovieTrackingTrack *track, MovieTrackingMarker *marker,
379                         float co[2], int width, int height)
380 {
381         float pos[2], dx, dy;
382
383         add_v2_v2v2(pos, marker->pos, track->offset);
384
385         dx= 12.0f/width/sc->zoom;
386         dy= 12.0f/height/sc->zoom;
387
388         dx=MIN2(dx, (track->pat_max[0]-track->pat_min[0])/2.0f);
389         dy=MIN2(dy, (track->pat_max[1]-track->pat_min[1])/2.0f);
390
391         return co[0]>=pos[0]-dx && co[0]<=pos[0]+dx && co[1]>=pos[1]-dy && co[1]<=pos[1]+dy;
392 }
393
394 static void hide_cursor(bContext *C)
395 {
396         wmWindow *win= CTX_wm_window(C);
397
398         WM_cursor_set(win, CURSOR_NONE);
399 }
400
401 static void show_cursor(bContext *C)
402 {
403         wmWindow *win= CTX_wm_window(C);
404
405         WM_cursor_set(win, CURSOR_STD);
406 }
407
408 static void *slide_marker_customdata(bContext *C, wmEvent *event)
409 {
410         SpaceClip *sc= CTX_wm_space_clip(C);
411         MovieClip *clip= ED_space_clip(sc);
412         MovieTrackingTrack *track;
413         int width, height;
414         float co[2];
415         void *customdata= NULL;
416         ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
417
418         ED_space_clip_size(sc, &width, &height);
419
420         if(width==0 || height==0)
421                 return NULL;
422
423         ED_clip_mouse_pos(C, event, co);
424
425         track= tracksbase->first;
426         while(track) {
427                 if(TRACK_VIEW_SELECTED(sc, track) && (track->flag&TRACK_LOCKED)==0) {
428                         MovieTrackingMarker *marker= BKE_tracking_get_marker(track, sc->user.framenr);
429
430                         if((marker->flag&MARKER_DISABLED)==0) {
431                                 if(!customdata)
432                                         if(mouse_on_offset(sc, track, marker, co, width, height))
433                                                 customdata= create_slide_marker_data(sc, track, marker, event, TRACK_AREA_POINT, SLIDE_ACTION_POS, width, height);
434
435                                 if(sc->flag&SC_SHOW_MARKER_SEARCH) {
436                                         if(mouse_on_corner(sc, track, marker, TRACK_AREA_SEARCH, co, 1, width, height))
437                                                 customdata= create_slide_marker_data(sc, track, marker, event, TRACK_AREA_SEARCH, SLIDE_ACTION_OFFSET, width, height);
438                                         else if(mouse_on_corner(sc, track, marker, TRACK_AREA_SEARCH, co, 0, width, height))
439                                                 customdata= create_slide_marker_data(sc, track, marker, event, TRACK_AREA_SEARCH, SLIDE_ACTION_SIZE, width, height);
440                                 }
441
442                                 if(!customdata && sc->flag&SC_SHOW_MARKER_PATTERN) {
443                                         if(mouse_on_corner(sc, track, marker, TRACK_AREA_PAT, co, 1,  width, height))
444                                                 customdata= create_slide_marker_data(sc, track, marker, event, TRACK_AREA_PAT, SLIDE_ACTION_OFFSET, width, height);
445
446                                         if(!customdata && mouse_on_corner(sc, track, marker, TRACK_AREA_PAT, co, 0, width, height))
447                                                 customdata= create_slide_marker_data(sc, track, marker, event, TRACK_AREA_PAT, SLIDE_ACTION_SIZE, width, height);
448                                 }
449
450                                 if(customdata)
451                                         break;
452                         }
453                 }
454
455                 track= track->next;
456         }
457
458         return customdata;
459 }
460
461 static int slide_marker_invoke(bContext *C, wmOperator *op, wmEvent *event)
462 {
463         SlideMarkerData *slidedata= slide_marker_customdata(C, event);
464
465         if(slidedata) {
466                 SpaceClip *sc= CTX_wm_space_clip(C);
467                 MovieClip *clip= ED_space_clip(sc);
468                 MovieTracking *tracking= &clip->tracking;
469
470                 tracking->act_track= slidedata->track;
471
472                 op->customdata= slidedata;
473
474                 hide_cursor(C);
475                 WM_event_add_modal_handler(C, op);
476
477                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, NULL);
478
479                 return OPERATOR_RUNNING_MODAL;
480         }
481
482         return OPERATOR_PASS_THROUGH;
483 }
484
485 static void cancel_mouse_slide(SlideMarkerData *data)
486 {
487         /* cancel sliding */
488         if(data->area == TRACK_AREA_POINT) {
489                 if(data->action==SLIDE_ACTION_OFFSET)
490                         copy_v2_v2(data->offset, data->soff);
491                 else
492                         copy_v2_v2(data->pos, data->spos);
493         } else {
494                 if(data->action==SLIDE_ACTION_SIZE) {
495                         copy_v2_v2(data->min, data->smin);
496                         copy_v2_v2(data->max, data->smax);
497                 } else {
498                         int a;
499
500                         for(a= 0; a<data->track->markersnr; a++)
501                                 copy_v2_v2(data->track->markers[a].pos, data->smarkers[a]);
502
503                         copy_v2_v2(data->offset, data->soff);
504                 }
505         }
506 }
507
508 static void free_slide_data(SlideMarkerData *data)
509 {
510         if(data->smarkers) MEM_freeN(data->smarkers);
511         MEM_freeN(data);
512 }
513
514 static int slide_marker_modal(bContext *C, wmOperator *op, wmEvent *event)
515 {
516         SpaceClip *sc= CTX_wm_space_clip(C);
517         SlideMarkerData *data= (SlideMarkerData *)op->customdata;
518         float dx, dy, mdelta[2];
519
520         switch(event->type) {
521                 case LEFTCTRLKEY:
522                 case RIGHTCTRLKEY:
523                 case LEFTSHIFTKEY:
524                 case RIGHTSHIFTKEY:
525                         if(data->action==SLIDE_ACTION_SIZE)
526                                 if(ELEM(event->type, LEFTCTRLKEY, RIGHTCTRLKEY))
527                                         data->lock= event->val==KM_RELEASE;
528
529                         if(ELEM(event->type, LEFTSHIFTKEY, RIGHTSHIFTKEY))
530                                 data->accurate= event->val==KM_PRESS;
531
532                         /* no break! update area size */
533
534                 case MOUSEMOVE:
535                         mdelta[0]= event->mval[0]-data->mval[0];
536                         mdelta[1]= event->mval[1]-data->mval[1];
537
538                         dx= mdelta[0]/data->width/sc->zoom;
539
540                         if(data->lock) dy= -dx/data->height*data->width;
541                         else dy= mdelta[1]/data->height/sc->zoom;
542
543                         if(data->accurate) {
544                                 dx/= 5;
545                                 dy/= 5;
546                         }
547
548                         if(data->area==TRACK_AREA_POINT) {
549                                 if(data->action==SLIDE_ACTION_OFFSET) {
550                                         data->offset[0]= data->soff[0]+dx;
551                                         data->offset[1]= data->soff[1]+dy;
552                                 } else {
553                                         data->pos[0]= data->spos[0]+dx;
554                                         data->pos[1]= data->spos[1]+dy;
555
556                                         data->marker->flag&= ~MARKER_TRACKED;
557                                 }
558
559                                 WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
560                                 DAG_id_tag_update(&sc->clip->id, 0);
561                         } else {
562                                 if(data->action==SLIDE_ACTION_SIZE) {
563                                         data->min[0]= data->smin[0]-dx;
564                                         data->max[0]= data->smax[0]+dx;
565
566                                         data->min[1]= data->smin[1]+dy;
567                                         data->max[1]= data->smax[1]-dy;
568
569                                         if(data->area==TRACK_AREA_SEARCH) BKE_tracking_clamp_track(data->track, CLAMP_SEARCH_DIM);
570                                         else BKE_tracking_clamp_track(data->track, CLAMP_PAT_DIM);
571                                 } else {
572                                         float d[2]={dx, dy};
573
574                                         if(data->area==TRACK_AREA_SEARCH) {
575                                                 add_v2_v2v2(data->min, data->smin, d);
576                                                 add_v2_v2v2(data->max, data->smax, d);
577                                         } else {
578                                                 int a;
579
580                                                 for(a= 0; a<data->track->markersnr; a++)
581                                                         add_v2_v2v2(data->track->markers[a].pos, data->smarkers[a], d);
582
583                                                 sub_v2_v2v2(data->offset, data->soff, d);
584                                         }
585
586                                         if(data->area==TRACK_AREA_SEARCH)
587                                                 BKE_tracking_clamp_track(data->track, CLAMP_SEARCH_POS);
588                                 }
589                         }
590
591                         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, NULL);
592
593                         break;
594
595                 case LEFTMOUSE:
596                         if(event->val==KM_RELEASE) {
597                                 free_slide_data(op->customdata);
598
599                                 show_cursor(C);
600
601                                 return OPERATOR_FINISHED;
602                         }
603
604                         break;
605
606                 case ESCKEY:
607                         cancel_mouse_slide(op->customdata);
608
609                         free_slide_data(op->customdata);
610
611                         show_cursor(C);
612
613                         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, NULL);
614
615                         return OPERATOR_CANCELLED;
616         }
617
618         return OPERATOR_RUNNING_MODAL;
619 }
620
621 void CLIP_OT_slide_marker(wmOperatorType *ot)
622 {
623         /* identifiers */
624         ot->name= "Slide Marker";
625         ot->description= "Slide marker areas";
626         ot->idname= "CLIP_OT_slide_marker";
627
628         /* api callbacks */
629         ot->poll= space_clip_frame_poll;
630         ot->invoke= slide_marker_invoke;
631         ot->modal= slide_marker_modal;
632
633         /* flags */
634         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_GRAB_POINTER|OPTYPE_BLOCKING;
635
636         /* properties */
637         RNA_def_float_vector(ot->srna, "offset", 2, NULL, -FLT_MAX, FLT_MAX,
638                 "Offset", "Offset in floating point units, 1.0 is the width and height of the image", -FLT_MAX, FLT_MAX);
639 }
640
641 /********************** mouse select operator *********************/
642
643 static int mouse_on_side(float co[2], float x1, float y1, float x2, float y2, float epsx, float epsy)
644 {
645         if(x1>x2) SWAP(float, x1, x2);
646         if(y1>y2) SWAP(float, y1, y2);
647
648         return (co[0]>=x1-epsx && co[0]<=x2+epsx) && (co[1]>=y1-epsy && co[1]<=y2+epsy);
649 }
650
651 static int mouse_on_rect(float co[2], float pos[2], float min[2], float max[2], float epsx, float epsy)
652 {
653         return mouse_on_side(co, pos[0]+min[0], pos[1]+min[1], pos[0]+max[0], pos[1]+min[1], epsx, epsy) ||
654                mouse_on_side(co, pos[0]+min[0], pos[1]+min[1], pos[0]+min[0], pos[1]+max[1], epsx, epsy) ||
655                mouse_on_side(co, pos[0]+min[0], pos[1]+max[1], pos[0]+max[0], pos[1]+max[1], epsx, epsy) ||
656                mouse_on_side(co, pos[0]+max[0], pos[1]+min[1], pos[0]+max[0], pos[1]+max[1], epsx, epsy);
657 }
658
659 static int track_mouse_area(SpaceClip *sc, float co[2], MovieTrackingTrack *track)
660 {
661         MovieTrackingMarker *marker= BKE_tracking_get_marker(track, sc->user.framenr);
662         float epsx, epsy;
663         int width, height;
664
665         ED_space_clip_size(sc, &width, &height);
666
667         epsx= MIN4(track->pat_min[0]-track->search_min[0], track->search_max[0]-track->pat_max[0],
668                    fabsf(track->pat_min[0]), fabsf(track->pat_max[0])) / 2;
669         epsy= MIN4(track->pat_min[1]-track->search_min[1], track->search_max[1]-track->pat_max[1],
670                    fabsf(track->pat_min[1]), fabsf(track->pat_max[1])) / 2;
671
672         epsx= MAX2(epsx, 2.0f / width);
673         epsy= MAX2(epsy, 2.0f / height);
674
675         if(sc->flag&SC_SHOW_MARKER_SEARCH)
676                 if(mouse_on_rect(co, marker->pos, track->search_min, track->search_max, epsx, epsy))
677                         return TRACK_AREA_SEARCH;
678
679         if((marker->flag&MARKER_DISABLED)==0) {
680                 if(sc->flag&SC_SHOW_MARKER_PATTERN)
681                         if(mouse_on_rect(co, marker->pos, track->pat_min, track->pat_max, epsx, epsy))
682                                 return TRACK_AREA_PAT;
683
684                 epsx= 12.0f/width;
685                 epsy= 12.0f/height;
686
687                 if(fabsf(co[0]-marker->pos[0]-track->offset[0])< epsx && fabsf(co[1]-marker->pos[1]-track->offset[1])<=epsy)
688                         return TRACK_AREA_POINT;
689         }
690
691         return TRACK_AREA_NONE;
692 }
693
694 static float dist_to_rect(float co[2], float pos[2], float min[2], float max[2])
695 {
696         float d1, d2, d3, d4;
697         float p[2]= {co[0]-pos[0], co[1]-pos[1]};
698         float v1[2]= {min[0], min[1]}, v2[2]= {max[0], min[1]},
699               v3[2]= {max[0], max[1]}, v4[2]= {min[0], max[1]};
700
701         d1= dist_to_line_segment_v2(p, v1, v2);
702         d2= dist_to_line_segment_v2(p, v2, v3);
703         d3= dist_to_line_segment_v2(p, v3, v4);
704         d4= dist_to_line_segment_v2(p, v4, v1);
705
706         return MIN4(d1, d2, d3, d4);
707 }
708
709 static MovieTrackingTrack *find_nearest_track(SpaceClip *sc, ListBase *tracksbase, float co[2])
710 {
711         MovieTrackingTrack *track= NULL, *cur;
712         float mindist= 0.0f;
713
714         cur= tracksbase->first;
715         while(cur) {
716                 MovieTrackingMarker *marker= BKE_tracking_get_marker(cur, sc->user.framenr);
717
718                 if(((cur->flag&TRACK_HIDDEN)==0) && MARKER_VISIBLE(sc, marker)) {
719                         float dist, d1, d2=FLT_MAX, d3=FLT_MAX;
720
721                         d1= sqrtf((co[0]-marker->pos[0]-cur->offset[0])*(co[0]-marker->pos[0]-cur->offset[0])+
722                                           (co[1]-marker->pos[1]-cur->offset[1])*(co[1]-marker->pos[1]-cur->offset[1])); /* distance to marker point */
723
724                         /* distance to pattern boundbox */
725                         if(sc->flag&SC_SHOW_MARKER_PATTERN)
726                                 d2= dist_to_rect(co, marker->pos, cur->pat_min, cur->pat_max);
727
728                         /* distance to search boundbox */
729                         if(sc->flag&SC_SHOW_MARKER_SEARCH && TRACK_VIEW_SELECTED(sc, cur))
730                                 d3= dist_to_rect(co, marker->pos, cur->search_min, cur->search_max);
731
732                         /* choose minimal distance. useful for cases of overlapped markers. */
733                         dist= MIN3(d1, d2, d3);
734
735                         if(track==NULL || dist<mindist) {
736                                 track= cur;
737                                 mindist= dist;
738                         }
739                 }
740
741                 cur= cur->next;
742         }
743
744         return track;
745 }
746
747 static int mouse_select(bContext *C, float co[2], int extend)
748 {
749         SpaceClip *sc= CTX_wm_space_clip(C);
750         MovieClip *clip= ED_space_clip(sc);
751         MovieTracking *tracking= &clip->tracking;
752         ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
753         MovieTrackingTrack *act_track= BKE_tracking_active_track(tracking);
754         MovieTrackingTrack *track= NULL;        /* selected marker */
755
756         track= find_nearest_track(sc, tracksbase, co);
757
758         if(track) {
759                 int area= track_mouse_area(sc, co, track);
760
761                 if(!extend || !TRACK_VIEW_SELECTED(sc, track))
762                         area= TRACK_AREA_ALL;
763
764                 if(extend && TRACK_AREA_SELECTED(track, area)) {
765                         if(track==act_track)
766                                 BKE_tracking_deselect_track(track, area);
767                         else
768                                 clip->tracking.act_track= track;
769                 } else {
770                         if(area==TRACK_AREA_POINT)
771                                 area= TRACK_AREA_ALL;
772
773                         BKE_tracking_select_track(tracksbase, track, area, extend);
774                         clip->tracking.act_track= track;
775                 }
776         }
777
778         if(!extend) {
779                 sc->xlockof= 0.0f;
780                 sc->ylockof= 0.0f;
781         }
782
783         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, NULL);
784
785         return OPERATOR_FINISHED;
786 }
787
788 static int select_exec(bContext *C, wmOperator *op)
789 {
790         float co[2];
791         int extend;
792
793         RNA_float_get_array(op->ptr, "location", co);
794         extend= RNA_boolean_get(op->ptr, "extend");
795
796         return mouse_select(C, co, extend);
797 }
798
799 static int select_invoke(bContext *C, wmOperator *op, wmEvent *event)
800 {
801         float co[2];
802         int extend= RNA_boolean_get(op->ptr, "extend");
803
804         if(!extend) {
805                 SlideMarkerData *slidedata= slide_marker_customdata(C, event);
806
807                 if(slidedata) {
808                         SpaceClip *sc= CTX_wm_space_clip(C);
809                         MovieClip *clip= ED_space_clip(sc);
810
811                         clip->tracking.act_track= slidedata->track;
812
813                         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, NULL);
814
815                         MEM_freeN(slidedata);
816
817                         return OPERATOR_PASS_THROUGH;
818                 }
819         }
820
821         ED_clip_mouse_pos(C, event, co);
822         RNA_float_set_array(op->ptr, "location", co);
823
824         return select_exec(C, op);
825 }
826
827 void CLIP_OT_select(wmOperatorType *ot)
828 {
829         /* identifiers */
830         ot->name= "Select";
831         ot->description= "Select tracking markers";
832         ot->idname= "CLIP_OT_select";
833
834         /* api callbacks */
835         ot->exec= select_exec;
836         ot->invoke= select_invoke;
837         ot->poll= ED_space_clip_poll;
838
839         /* flags */
840         ot->flag= OPTYPE_UNDO;
841
842         /* properties */
843         RNA_def_boolean(ot->srna, "extend", 0,
844                 "Extend", "Extend selection rather than clearing the existing selection");
845         RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
846                 "Location", "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds", -100.0f, 100.0f);
847 }
848
849 /********************** border select operator *********************/
850
851 static int border_select_exec(bContext *C, wmOperator *op)
852 {
853         SpaceClip *sc= CTX_wm_space_clip(C);
854         MovieClip *clip= ED_space_clip(sc);
855         MovieTrackingTrack *track;
856         ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
857         rcti rect;
858         rctf rectf;
859         int change= 0, mode, extend;
860
861         /* get rectangle from operator */
862         rect.xmin= RNA_int_get(op->ptr, "xmin");
863         rect.ymin= RNA_int_get(op->ptr, "ymin");
864         rect.xmax= RNA_int_get(op->ptr, "xmax");
865         rect.ymax= RNA_int_get(op->ptr, "ymax");
866
867         ED_clip_point_stable_pos(C, rect.xmin, rect.ymin, &rectf.xmin, &rectf.ymin);
868         ED_clip_point_stable_pos(C, rect.xmax, rect.ymax, &rectf.xmax, &rectf.ymax);
869
870         mode= RNA_int_get(op->ptr, "gesture_mode");
871         extend= RNA_boolean_get(op->ptr, "extend");
872
873         /* do actual selection */
874         track= tracksbase->first;
875         while(track) {
876                 if((track->flag&TRACK_HIDDEN)==0) {
877                         MovieTrackingMarker *marker= BKE_tracking_get_marker(track, sc->user.framenr);
878
879                         if(MARKER_VISIBLE(sc, marker)) {
880                                 if(BLI_in_rctf(&rectf, marker->pos[0], marker->pos[1])) {
881                                         BKE_tracking_track_flag(track, TRACK_AREA_ALL, SELECT, mode!=GESTURE_MODAL_SELECT);
882                                 }
883                                 else if(!extend) {
884                                         BKE_tracking_track_flag(track, TRACK_AREA_ALL, SELECT, 1);
885                                 }
886
887                                 change= 1;
888                         }
889                 }
890
891                 track= track->next;
892         }
893
894         if(change) {
895                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, NULL);
896
897                 return OPERATOR_FINISHED;
898         }
899
900         return OPERATOR_CANCELLED;
901 }
902
903 void CLIP_OT_select_border(wmOperatorType *ot)
904 {
905         /* identifiers */
906         ot->name= "Border Select";
907         ot->description= "Select markers using border selection";
908         ot->idname= "CLIP_OT_select_border";
909
910         /* api callbacks */
911         ot->invoke= WM_border_select_invoke;
912         ot->exec= border_select_exec;
913         ot->modal= WM_border_select_modal;
914         ot->poll= ED_space_clip_poll;
915
916         /* flags */
917         ot->flag= OPTYPE_UNDO;
918
919         /* properties */
920         WM_operator_properties_gesture_border(ot, TRUE);
921 }
922
923 /********************** circle select operator *********************/
924
925 static int marker_inside_ellipse(MovieTrackingMarker *marker, float offset[2], float ellipse[2])
926 {
927         /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */
928         float x, y;
929
930         x= (marker->pos[0] - offset[0])*ellipse[0];
931         y= (marker->pos[1] - offset[1])*ellipse[1];
932
933         return x*x + y*y < 1.0f;
934 }
935
936 static int circle_select_exec(bContext *C, wmOperator *op)
937 {
938         SpaceClip *sc= CTX_wm_space_clip(C);
939         MovieClip *clip= ED_space_clip(sc);
940         ARegion *ar= CTX_wm_region(C);
941         MovieTrackingTrack *track;
942         ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
943         int x, y, radius, width, height, mode, change= 0;
944         float zoomx, zoomy, offset[2], ellipse[2];
945
946         /* get operator properties */
947         x= RNA_int_get(op->ptr, "x");
948         y= RNA_int_get(op->ptr, "y");
949         radius= RNA_int_get(op->ptr, "radius");
950
951         mode= RNA_int_get(op->ptr, "gesture_mode");
952
953         /* compute ellipse and position in unified coordinates */
954         ED_space_clip_size(sc, &width, &height);
955         ED_space_clip_zoom(sc, ar, &zoomx, &zoomy);
956
957         ellipse[0]= width*zoomx/radius;
958         ellipse[1]= height*zoomy/radius;
959
960         ED_clip_point_stable_pos(C, x, y, &offset[0], &offset[1]);
961
962         /* do selection */
963         track= tracksbase->first;
964         while(track) {
965                 if((track->flag&TRACK_HIDDEN)==0) {
966                         MovieTrackingMarker *marker= BKE_tracking_get_marker(track, sc->user.framenr);
967
968                         if(MARKER_VISIBLE(sc, marker) && marker_inside_ellipse(marker, offset, ellipse)) {
969                                 BKE_tracking_track_flag(track, TRACK_AREA_ALL, SELECT, mode!=GESTURE_MODAL_SELECT);
970
971                                 change= 1;
972                         }
973                 }
974
975                 track= track->next;
976         }
977
978         if(change) {
979                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, NULL);
980
981                 return OPERATOR_FINISHED;
982         }
983
984         return OPERATOR_CANCELLED;
985 }
986
987 void CLIP_OT_select_circle(wmOperatorType *ot)
988 {
989         /* identifiers */
990         ot->name= "Circle Select";
991         ot->description= "Select markers using circle selection";
992         ot->idname= "CLIP_OT_select_circle";
993
994         /* api callbacks */
995         ot->invoke= WM_gesture_circle_invoke;
996         ot->modal= WM_gesture_circle_modal;
997         ot->exec= circle_select_exec;
998         ot->poll= ED_space_clip_poll;
999
1000         /* flags */
1001         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1002
1003         /* properties */
1004         RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
1005         RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
1006         RNA_def_int(ot->srna, "radius", 0, INT_MIN, INT_MAX, "Radius", "", INT_MIN, INT_MAX);
1007         RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Gesture Mode", "", INT_MIN, INT_MAX);
1008 }
1009
1010 /********************** select all operator *********************/
1011
1012 static int select_all_exec(bContext *C, wmOperator *op)
1013 {
1014         SpaceClip *sc= CTX_wm_space_clip(C);
1015         MovieClip *clip= ED_space_clip(sc);
1016         MovieTrackingTrack *track= NULL;        /* selected track */
1017         ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
1018         int action= RNA_enum_get(op->ptr, "action");
1019         int framenr= sc->user.framenr;
1020         int has_selection= 0;
1021
1022         if(action == SEL_TOGGLE){
1023                 action= SEL_SELECT;
1024                 track= tracksbase->first;
1025                 while(track) {
1026                         if(TRACK_VIEW_SELECTED(sc, track)) {
1027                                 action= SEL_DESELECT;
1028                                 break;
1029                         }
1030
1031                         track= track->next;
1032                 }
1033         }
1034
1035         track= tracksbase->first;
1036         while(track) {
1037                 if((track->flag&TRACK_HIDDEN)==0) {
1038                         MovieTrackingMarker *marker= BKE_tracking_get_marker(track, framenr);
1039
1040                         if(marker && MARKER_VISIBLE(sc, marker)) {
1041                                 switch (action) {
1042                                         case SEL_SELECT:
1043                                                 track->flag|= SELECT;
1044                                                 track->pat_flag|= SELECT;
1045                                                 track->search_flag|= SELECT;
1046                                                 break;
1047                                         case SEL_DESELECT:
1048                                                 track->flag&= ~SELECT;
1049                                                 track->pat_flag&= ~SELECT;
1050                                                 track->search_flag&= ~SELECT;
1051                                                 break;
1052                                         case SEL_INVERT:
1053                                                 track->flag^= SELECT;
1054                                                 track->pat_flag^= SELECT;
1055                                                 track->search_flag^= SELECT;
1056                                                 break;
1057                                 }
1058                         }
1059                 }
1060
1061                 if(TRACK_VIEW_SELECTED(sc, track))
1062                         has_selection= 1;
1063
1064                 track= track->next;
1065         }
1066
1067         if(!has_selection)
1068                 sc->flag&= ~SC_LOCK_SELECTION;
1069
1070         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, NULL);
1071
1072         return OPERATOR_FINISHED;
1073 }
1074
1075 void CLIP_OT_select_all(wmOperatorType *ot)
1076 {
1077         /* identifiers */
1078         ot->name= "Select or Deselect All";
1079         ot->description= "Change selection of all tracking markers";
1080         ot->idname= "CLIP_OT_select_all";
1081
1082         /* api callbacks */
1083         ot->exec= select_all_exec;
1084         ot->poll= ED_space_clip_poll;
1085
1086         /* flags */
1087         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1088
1089         WM_operator_properties_select_all(ot);
1090 }
1091
1092 /********************** select grouped operator *********************/
1093
1094 static int select_groped_exec(bContext *C, wmOperator *op)
1095 {
1096         SpaceClip *sc= CTX_wm_space_clip(C);
1097         MovieClip *clip= ED_space_clip(sc);
1098         MovieTrackingTrack *track;
1099         MovieTrackingMarker *marker;
1100         MovieTracking *tracking= &clip->tracking;
1101         ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
1102         int group= RNA_enum_get(op->ptr, "group");
1103
1104         track= tracksbase->first;
1105         while(track) {
1106                 int ok= 0;
1107
1108                 marker= BKE_tracking_get_marker(track, sc->user.framenr);
1109
1110                 if(group==0) { /* Keyframed */
1111                         ok= marker->framenr==sc->user.framenr && (marker->flag&MARKER_TRACKED)==0;
1112                 }
1113                 else if(group==1) { /* Estimated */
1114                         ok= marker->framenr!=sc->user.framenr;
1115                 }
1116                 else if(group==2) { /* tracked */
1117                         ok= marker->framenr==sc->user.framenr && (marker->flag&MARKER_TRACKED);
1118                 }
1119                 else if(group==3) { /* locked */
1120                         ok= track->flag&TRACK_LOCKED;
1121                 }
1122                 else if(group==4) { /* disabled */
1123                         ok= marker->flag&MARKER_DISABLED;
1124                 }
1125                 else if(group==5) { /* color */
1126                         MovieTrackingTrack *act_track= BKE_tracking_active_track(tracking);
1127
1128                         if(act_track) {
1129                                 ok= (track->flag&TRACK_CUSTOMCOLOR) == (act_track->flag&TRACK_CUSTOMCOLOR);
1130
1131                                 if(ok && track->flag&TRACK_CUSTOMCOLOR)
1132                                         ok= equals_v3v3(track->color, act_track->color);
1133                         }
1134                 }
1135                 else if(group==6) { /* failed */
1136                         ok= (track->flag&TRACK_HAS_BUNDLE) == 0;
1137                 }
1138
1139                 if(ok) {
1140                         track->flag|= SELECT;
1141                         if(sc->flag&SC_SHOW_MARKER_PATTERN) track->pat_flag|= SELECT;;
1142                         if(sc->flag&SC_SHOW_MARKER_SEARCH) track->search_flag|= SELECT;;
1143                 }
1144
1145                 track= track->next;
1146         }
1147
1148         WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, clip);
1149
1150         return OPERATOR_FINISHED;
1151 }
1152
1153 void CLIP_OT_select_grouped(wmOperatorType *ot)
1154 {
1155         static EnumPropertyItem select_group_items[] = {
1156                         {0, "KEYFRAMED", 0, "Keyframed tracks", "Select all keyframed tracks"},
1157                         {1, "ESTIMATED", 0, "Estimated tracks", "Select all estimated tracks"},
1158                         {2, "TRACKED", 0, "Tracked tracks", "Select all tracked tracks"},
1159                         {3, "LOCKED", 0, "Locked tracks", "Select all locked tracks"},
1160                         {4, "DISABLED", 0, "Disabled tracks", "Select all disabled tracks"},
1161                         {5, "COLOR", 0, "Tracks with same color", "Select all tracks with same color as active track"},
1162                         {6, "FAILED", 0, "Failed Tracks", "Select all tracks which failed to be reconstructed"},
1163                         {0, NULL, 0, NULL, NULL}
1164         };
1165
1166         /* identifiers */
1167         ot->name= "Select Grouped";
1168         ot->description= "Joint Selected Tracks";
1169         ot->idname= "CLIP_OT_select_grouped";
1170
1171         /* api callbacks */
1172         ot->exec= select_groped_exec;
1173         ot->poll= space_clip_frame_poll;
1174
1175         /* flags */
1176         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1177
1178         /* proeprties */
1179         RNA_def_enum(ot->srna, "group", select_group_items, TRACK_CLEAR_REMAINED, "Action", "Clear action to execute");
1180 }
1181
1182 /********************** track operator *********************/
1183
1184 typedef struct TrackMarkersJob {
1185         struct MovieTrackingContext *context;   /* tracking context */
1186         int sfra, efra, lastfra;        /* Start, end and recently tracked frames */
1187         int backwards;                          /* Backwards tracking flag */
1188         MovieClip *clip;                        /* Clip which is tracking */
1189         float delay;                            /* Delay in milliseconds to allow tracking at fixed FPS */
1190
1191         struct Main *main;
1192         struct Scene *scene;
1193         struct bScreen *screen;
1194 } TrackMarkersJob;
1195
1196 static int track_markers_testbreak(void)
1197 {
1198         return G.afbreek;
1199 }
1200
1201 static int track_count_markers(SpaceClip *sc, MovieClip *clip)
1202 {
1203         int tot= 0;
1204         ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
1205         MovieTrackingTrack *track;
1206         int framenr= sc->user.framenr;
1207
1208         track= tracksbase->first;
1209         while(track) {
1210                 if(TRACK_VIEW_SELECTED(sc, track) && (track->flag&TRACK_LOCKED)==0) {
1211                         MovieTrackingMarker *marker= BKE_tracking_exact_marker(track, framenr);
1212
1213                         if (!marker || (marker->flag&MARKER_DISABLED) == 0)
1214                                 tot++;
1215                 }
1216
1217                 track= track->next;
1218         }
1219
1220         return tot;
1221 }
1222
1223 static void clear_invisible_track_selection(SpaceClip *sc, MovieClip *clip)
1224 {
1225         ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
1226         int hidden = 0;
1227
1228         if ((sc->flag&SC_SHOW_MARKER_PATTERN)==0)
1229                 hidden |= TRACK_AREA_PAT;
1230
1231         if ((sc->flag&SC_SHOW_MARKER_SEARCH)==0)
1232                 hidden |= TRACK_AREA_SEARCH;
1233
1234         if (hidden) {
1235                 MovieTrackingTrack *track = tracksbase->first;
1236
1237                 while(track) {
1238                         BKE_tracking_track_flag(track, hidden, SELECT, 1);
1239
1240                         track = track->next;
1241                 }
1242         }
1243 }
1244
1245 static void track_init_markers(SpaceClip *sc, MovieClip *clip, int *frames_limit_r)
1246 {
1247         ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
1248         MovieTrackingTrack *track;
1249         int framenr= sc->user.framenr;
1250         int frames_limit= 0;
1251
1252         clear_invisible_track_selection(sc, clip);
1253
1254         track= tracksbase->first;
1255         while(track) {
1256                 if(TRACK_SELECTED(track)) {
1257                         if((track->flag&TRACK_HIDDEN)==0 && (track->flag&TRACK_LOCKED)==0) {
1258                                 BKE_tracking_ensure_marker(track, framenr);
1259
1260                                 if(track->frames_limit) {
1261                                         if(frames_limit==0)
1262                                                 frames_limit= track->frames_limit;
1263                                         else
1264                                                 frames_limit= MIN2(frames_limit, track->frames_limit);
1265                                 }
1266                         }
1267                 }
1268
1269                 track= track->next;
1270         }
1271
1272         *frames_limit_r= frames_limit;
1273 }
1274
1275 static int track_markers_check_direction(int backwards, int curfra, int efra)
1276 {
1277         if(backwards) {
1278                 if(curfra<efra) return 0;
1279         }
1280         else {
1281                 if(curfra>efra) return 0;
1282         }
1283
1284         return 1;
1285 }
1286
1287 static int track_markers_initjob(bContext *C, TrackMarkersJob *tmj, int backwards)
1288 {
1289         SpaceClip *sc= CTX_wm_space_clip(C);
1290         MovieClip *clip= ED_space_clip(sc);
1291         Scene *scene= CTX_data_scene(C);
1292         MovieTrackingSettings *settings= &clip->tracking.settings;
1293         int frames_limit;
1294
1295         track_init_markers(sc, clip, &frames_limit);
1296
1297         tmj->sfra= sc->user.framenr;
1298         tmj->clip= clip;
1299         tmj->backwards= backwards;
1300
1301         if(backwards) tmj->efra= SFRA;
1302         else tmj->efra= EFRA;
1303
1304         /* limit frames to be tracked by user setting */
1305         if(frames_limit) {
1306                 if(backwards) tmj->efra= MAX2(tmj->efra, tmj->sfra-frames_limit);
1307                 else tmj->efra= MIN2(tmj->efra, tmj->sfra+frames_limit);
1308         }
1309
1310         if(settings->speed!=TRACKING_SPEED_FASTEST) {
1311                 tmj->delay= 1.0f/scene->r.frs_sec*1000.0f;
1312
1313                 if(settings->speed==TRACKING_SPEED_HALF) tmj->delay*= 2;
1314                 else if(settings->speed==TRACKING_SPEED_QUARTER) tmj->delay*= 4;
1315                 else if(settings->speed==TRACKING_SPEED_DOUBLE) tmj->delay/= 2;
1316         }
1317
1318         tmj->context= BKE_tracking_context_new(clip, &sc->user, backwards, 1);
1319
1320         clip->tracking_context= tmj->context;
1321
1322         tmj->lastfra= tmj->sfra;
1323
1324         /* XXX: silly to store this, but this data is needed to update scene and movieclip
1325                 frame numbers when tracking is finished. This introduces better feedback for artists.
1326                 Maybe there's another way to solve this problem, but can't think better way atm.
1327                 Anyway, this way isn't more unstable as animation rendering animation
1328                 which uses the same approach (except storing screen). */
1329         tmj->scene= scene;
1330         tmj->main= CTX_data_main(C);
1331         tmj->screen= CTX_wm_screen(C);
1332
1333         return track_markers_check_direction(backwards, tmj->sfra, tmj->efra);
1334 }
1335
1336 static void track_markers_startjob(void *tmv, short *stop, short *do_update, float *progress)
1337 {
1338         TrackMarkersJob *tmj= (TrackMarkersJob *)tmv;
1339         int framenr= tmj->sfra;
1340         //double t= PIL_check_seconds_timer();
1341
1342         while(framenr != tmj->efra) {
1343                 if(tmj->delay>0) {
1344                         /* tracking should happen with fixed fps. Calculate time
1345                            using current timer value before tracking frame and after.
1346
1347                            Small (and maybe unneeded optimization): do not calculate exec_time
1348                            for "Fastest" tracking */
1349
1350                         double start_time= PIL_check_seconds_timer(), exec_time;
1351
1352                         if(!BKE_tracking_next(tmj->context))
1353                                 break;
1354
1355                         exec_time= PIL_check_seconds_timer()-start_time;
1356                         if(tmj->delay > (float)exec_time)
1357                                 PIL_sleep_ms(tmj->delay-(float)exec_time);
1358                 } else if(!BKE_tracking_next(tmj->context))
1359                                 break;
1360
1361                 *do_update= 1;
1362                 *progress=(float)(framenr-tmj->sfra) / (tmj->efra-tmj->sfra);
1363
1364                 if(tmj->backwards) framenr--;
1365                 else framenr++;
1366
1367                 tmj->lastfra= framenr;
1368
1369                 if(*stop || track_markers_testbreak())
1370                         break;
1371         }
1372
1373         //printf("Tracking time: %lf\n", PIL_check_seconds_timer()-t);
1374 }
1375
1376 static void track_markers_updatejob(void *tmv)
1377 {
1378         TrackMarkersJob *tmj= (TrackMarkersJob *)tmv;
1379
1380         BKE_tracking_sync(tmj->context);
1381 }
1382
1383 static void track_markers_freejob(void *tmv)
1384 {
1385         TrackMarkersJob *tmj= (TrackMarkersJob *)tmv;
1386
1387         tmj->clip->tracking_context= NULL;
1388         tmj->scene->r.cfra= tmj->lastfra;
1389         ED_update_for_newframe(tmj->main, tmj->scene, tmj->screen, 0);
1390
1391         BKE_tracking_sync(tmj->context);
1392         BKE_tracking_context_free(tmj->context);
1393
1394         MEM_freeN(tmj);
1395
1396         WM_main_add_notifier(NC_SCENE|ND_FRAME, tmj->scene);
1397 }
1398
1399 static int track_markers_exec(bContext *C, wmOperator *op)
1400 {
1401         SpaceClip *sc= CTX_wm_space_clip(C);
1402         MovieClip *clip= ED_space_clip(sc);
1403         Scene *scene= CTX_data_scene(C);
1404         struct MovieTrackingContext *context;
1405         int framenr= sc->user.framenr;
1406         int sfra= framenr, efra;
1407         int backwards= RNA_boolean_get(op->ptr, "backwards");
1408         int sequence= RNA_boolean_get(op->ptr, "sequence");
1409         int frames_limit;
1410
1411         if(track_count_markers(sc, clip)==0)
1412                 return OPERATOR_CANCELLED;
1413
1414         track_init_markers(sc, clip, &frames_limit);
1415
1416         if(backwards) efra= SFRA;
1417         else efra= EFRA;
1418
1419         /* limit frames to be tracked by user setting */
1420         if(frames_limit) {
1421                 if(backwards) efra= MAX2(efra, sfra-frames_limit);
1422                 else efra= MIN2(efra, sfra+frames_limit);
1423         }
1424
1425         if(!track_markers_check_direction(backwards, framenr, efra))
1426                 return OPERATOR_CANCELLED;
1427
1428         /* do not disable tracks due to threshold when tracking frame-by-frame */
1429         context= BKE_tracking_context_new(clip, &sc->user, backwards, sequence);
1430
1431         while(framenr != efra) {
1432                 if(!BKE_tracking_next(context))
1433                         break;
1434
1435                 if(backwards) framenr--;
1436                 else framenr++;
1437
1438                 if(!sequence)
1439                         break;
1440         }
1441
1442         BKE_tracking_sync(context);
1443         BKE_tracking_context_free(context);
1444
1445         /* update scene current frame to the lastes tracked frame */
1446         scene->r.cfra= framenr;
1447
1448         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
1449         WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
1450
1451         return OPERATOR_FINISHED;
1452 }
1453
1454 static int track_markers_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
1455 {
1456         TrackMarkersJob *tmj;
1457         ScrArea *sa= CTX_wm_area(C);
1458         SpaceClip *sc= CTX_wm_space_clip(C);
1459         MovieClip *clip= ED_space_clip(sc);
1460         wmJob *steve;
1461         int backwards= RNA_boolean_get(op->ptr, "backwards");
1462         int sequence= RNA_boolean_get(op->ptr, "sequence");
1463
1464         if(WM_jobs_test(CTX_wm_manager(C), CTX_wm_area(C))) {
1465                 /* only one tracking is allowed at a time */
1466                 return OPERATOR_CANCELLED;
1467         }
1468
1469         if(clip->tracking_context)
1470                 return OPERATOR_CANCELLED;
1471
1472         if(track_count_markers(sc, clip)==0)
1473                 return OPERATOR_CANCELLED;
1474
1475         if(!sequence)
1476                 return track_markers_exec(C, op);
1477
1478         tmj= MEM_callocN(sizeof(TrackMarkersJob), "TrackMarkersJob data");
1479         if(!track_markers_initjob(C, tmj, backwards)) {
1480                 track_markers_freejob(tmj);
1481
1482                 return OPERATOR_CANCELLED;
1483         }
1484
1485         /* setup job */
1486         steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), sa, "Track Markers", WM_JOB_PROGRESS);
1487         WM_jobs_customdata(steve, tmj, track_markers_freejob);
1488
1489         /* if there's delay set in tracking job, tracking should happen
1490            with fixed FPS. To deal with editor refresh we have to syncronize
1491            tracks from job and tracks in clip. Do this in timer callback
1492            to prevent threading conflicts. */
1493         if(tmj->delay>0) WM_jobs_timer(steve, tmj->delay/1000.0f, NC_MOVIECLIP|NA_EVALUATED, 0);
1494         else WM_jobs_timer(steve, 0.2, NC_MOVIECLIP|NA_EVALUATED, 0);
1495
1496         WM_jobs_callbacks(steve, track_markers_startjob, NULL, track_markers_updatejob, NULL);
1497
1498         G.afbreek= 0;
1499
1500         WM_jobs_start(CTX_wm_manager(C), steve);
1501         WM_cursor_wait(0);
1502
1503         /* add modal handler for ESC */
1504         WM_event_add_modal_handler(C, op);
1505
1506         return OPERATOR_RUNNING_MODAL;
1507 }
1508
1509 static int track_markers_modal(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
1510 {
1511         /* no running tracking, remove handler and pass through */
1512         if(0==WM_jobs_test(CTX_wm_manager(C), CTX_wm_area(C)))
1513                 return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
1514
1515         /* running tracking */
1516         switch (event->type) {
1517                 case ESCKEY:
1518                         return OPERATOR_RUNNING_MODAL;
1519                         break;
1520         }
1521
1522         return OPERATOR_PASS_THROUGH;
1523 }
1524
1525 void CLIP_OT_track_markers(wmOperatorType *ot)
1526 {
1527         /* identifiers */
1528         ot->name= "Track Markers";
1529         ot->description= "Track selected markers";
1530         ot->idname= "CLIP_OT_track_markers";
1531
1532         /* api callbacks */
1533         ot->exec= track_markers_exec;
1534         ot->invoke= track_markers_invoke;
1535         ot->poll= space_clip_frame_poll;
1536         ot->modal= track_markers_modal;
1537
1538         /* flags */
1539         ot->flag= OPTYPE_UNDO;
1540
1541         /* properties */
1542         RNA_def_boolean(ot->srna, "backwards", 0, "Backwards", "Do backwards tracking");
1543         RNA_def_boolean(ot->srna, "sequence", 0, "Track Sequence", "Track marker during image sequence rather than single image");
1544 }
1545
1546 /********************** solve camera operator *********************/
1547
1548 typedef struct {
1549         Scene *scene;
1550         MovieClip *clip;
1551         MovieClipUser user;
1552
1553         ReportList *reports;
1554
1555         char stats_message[256];
1556
1557         struct MovieReconstructContext *context;
1558 } SolveCameraJob;
1559
1560 static int solve_camera_initjob(bContext *C, SolveCameraJob *scj, wmOperator *op, char *error_msg, int max_error)
1561 {
1562         SpaceClip *sc= CTX_wm_space_clip(C);
1563         MovieClip *clip= ED_space_clip(sc);
1564         Scene *scene= CTX_data_scene(C);
1565         MovieTracking *tracking= &clip->tracking;
1566         MovieTrackingSettings *settings= &clip->tracking.settings;
1567         MovieTrackingObject *object= BKE_tracking_active_object(tracking);
1568         int width, height;
1569
1570         if(!BKE_tracking_can_reconstruct(tracking, object, error_msg, max_error))
1571                 return 0;
1572
1573         /* could fail if footage uses images with different sizes */
1574         BKE_movieclip_get_size(clip, &sc->user, &width, &height);
1575
1576         scj->clip= clip;
1577         scj->scene= scene;
1578         scj->reports= op->reports;
1579         scj->user= sc->user;
1580
1581         scj->context= BKE_tracking_reconstruction_context_new(tracking, object,
1582                         settings->keyframe1, settings->keyframe2, width, height);
1583
1584         tracking->stats= MEM_callocN(sizeof(MovieTrackingStats), "solve camera stats");
1585
1586         return 1;
1587 }
1588
1589 static void solve_camera_updatejob(void *scv)
1590 {
1591         SolveCameraJob *scj= (SolveCameraJob *)scv;
1592         MovieTracking *tracking= &scj->clip->tracking;
1593
1594         BLI_strncpy(tracking->stats->message, scj->stats_message, sizeof(tracking->stats->message));
1595 }
1596
1597 static void solve_camera_startjob(void *scv, short *stop, short *do_update, float *progress)
1598 {
1599         SolveCameraJob *scj= (SolveCameraJob *)scv;
1600
1601         BKE_tracking_solve_reconstruction(scj->context, stop, do_update, progress,
1602                         scj->stats_message, sizeof(scj->stats_message));
1603 }
1604
1605 static void solve_camera_freejob(void *scv)
1606 {
1607         SolveCameraJob *scj= (SolveCameraJob *)scv;
1608         MovieTracking *tracking= &scj->clip->tracking;
1609         Scene *scene= scj->scene;
1610         MovieClip *clip= scj->clip;
1611         int solved;
1612
1613         if(!scj->context) {
1614                 /* job weren't fully initialized due to some error */
1615                 MEM_freeN(scj);
1616                 return;
1617         }
1618
1619         solved= BKE_tracking_finish_reconstruction(scj->context, tracking);
1620
1621         if(!solved)
1622                 BKE_report(scj->reports, RPT_WARNING, "Some data failed to reconstruct, see console for details");
1623         else
1624                 BKE_reportf(scj->reports, RPT_INFO, "Average reprojection error %.3f", tracking->reconstruction.error);
1625
1626         /* set currently solved clip as active for scene */
1627         if(scene->clip)
1628                 id_us_min(&clip->id);
1629
1630         scene->clip= clip;
1631         id_us_plus(&clip->id);
1632
1633         /* set blender camera focal length so result would look fine there */
1634         if(scene->camera) {
1635                 Camera *camera= (Camera*)scene->camera->data;
1636                 int width, height;
1637
1638                 BKE_movieclip_get_size(clip, &scj->user, &width, &height);
1639
1640                 BKE_tracking_camera_to_blender(tracking, scene, camera, width, height);
1641
1642                 WM_main_add_notifier(NC_OBJECT, camera);
1643         }
1644
1645         MEM_freeN(tracking->stats);
1646         tracking->stats= NULL;
1647
1648         DAG_id_tag_update(&clip->id, 0);
1649
1650         WM_main_add_notifier(NC_MOVIECLIP|NA_EVALUATED, clip);
1651         WM_main_add_notifier(NC_OBJECT|ND_TRANSFORM, NULL);
1652
1653         /* update active clip displayed in scene buttons */
1654         WM_main_add_notifier(NC_SCENE, scene);
1655
1656         BKE_tracking_reconstruction_context_free(scj->context);
1657         MEM_freeN(scj);
1658 }
1659
1660 static int solve_camera_exec(bContext *C, wmOperator *op)
1661 {
1662         SolveCameraJob *scj;
1663         char error_msg[256]= "\0";
1664
1665         scj= MEM_callocN(sizeof(SolveCameraJob), "SolveCameraJob data");
1666         if(!solve_camera_initjob(C, scj, op, error_msg, sizeof(error_msg))) {
1667                 if(error_msg[0])
1668                         BKE_report(op->reports, RPT_ERROR, error_msg);
1669
1670                 solve_camera_freejob(scj);
1671
1672                 return OPERATOR_CANCELLED;
1673         }
1674
1675         solve_camera_startjob(scj, NULL, NULL, NULL);
1676
1677         solve_camera_freejob(scj);
1678
1679         return OPERATOR_FINISHED;
1680 }
1681
1682 static int solve_camera_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
1683 {
1684         SolveCameraJob *scj;
1685         ScrArea *sa= CTX_wm_area(C);
1686         SpaceClip *sc= CTX_wm_space_clip(C);
1687         MovieClip *clip= ED_space_clip(sc);
1688         MovieTracking *tracking= &clip->tracking;
1689         MovieTrackingReconstruction *reconstruction= BKE_tracking_get_reconstruction(tracking);
1690         wmJob *steve;
1691         char error_msg[256]= "\0";
1692
1693         if(WM_jobs_test(CTX_wm_manager(C), CTX_wm_area(C))) {
1694                 /* only one solve is allowed at a time */
1695                 return OPERATOR_CANCELLED;
1696         }
1697
1698         scj= MEM_callocN(sizeof(SolveCameraJob), "SolveCameraJob data");
1699         if(!solve_camera_initjob(C, scj, op, error_msg, sizeof(error_msg))) {
1700                 if(error_msg[0])
1701                         BKE_report(op->reports, RPT_ERROR, error_msg);
1702
1703                 solve_camera_freejob(scj);
1704
1705                 return OPERATOR_CANCELLED;
1706         }
1707
1708         BLI_strncpy(tracking->stats->message, "Solving camera | Preparing solve", sizeof(tracking->stats->message));
1709
1710         /* hide reconstruction statistics from previous solve */
1711         reconstruction->flag&= ~TRACKING_RECONSTRUCTED;
1712         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
1713
1714         /* setup job */
1715         steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), sa, "Solve Camera", WM_JOB_PROGRESS);
1716         WM_jobs_customdata(steve, scj, solve_camera_freejob);
1717         WM_jobs_timer(steve, 0.1, NC_MOVIECLIP|NA_EVALUATED, 0);
1718         WM_jobs_callbacks(steve, solve_camera_startjob, NULL, solve_camera_updatejob, NULL);
1719
1720         G.afbreek= 0;
1721
1722         WM_jobs_start(CTX_wm_manager(C), steve);
1723         WM_cursor_wait(0);
1724
1725         /* add modal handler for ESC */
1726         WM_event_add_modal_handler(C, op);
1727
1728         return OPERATOR_RUNNING_MODAL;
1729 }
1730
1731 static int solve_camera_modal(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
1732 {
1733         /* no running solver, remove handler and pass through */
1734         if(0==WM_jobs_test(CTX_wm_manager(C), CTX_wm_area(C)))
1735                 return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
1736
1737         /* running tracking */
1738         switch (event->type) {
1739                 case ESCKEY:
1740                         return OPERATOR_RUNNING_MODAL;
1741                         break;
1742         }
1743
1744         return OPERATOR_PASS_THROUGH;
1745 }
1746
1747 void CLIP_OT_solve_camera(wmOperatorType *ot)
1748 {
1749         /* identifiers */
1750         ot->name= "Solve Camera";
1751         ot->description= "Solve camera motion from tracks";
1752         ot->idname= "CLIP_OT_solve_camera";
1753
1754         /* api callbacks */
1755         ot->exec= solve_camera_exec;
1756         ot->invoke= solve_camera_invoke;
1757         ot->modal= solve_camera_modal;
1758         ot->poll= ED_space_clip_poll;
1759
1760         /* flags */
1761         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1762 }
1763
1764 /********************** clear solution operator *********************/
1765
1766 static int clear_solution_exec(bContext *C, wmOperator *UNUSED(op))
1767 {
1768         SpaceClip *sc= CTX_wm_space_clip(C);
1769         MovieClip *clip= ED_space_clip(sc);
1770         MovieTracking *tracking= &clip->tracking;
1771         ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
1772         MovieTrackingReconstruction *reconstruction= BKE_tracking_get_reconstruction(tracking);
1773         MovieTrackingTrack *track= tracksbase->first;
1774
1775         while(track) {
1776                 track->flag&= ~TRACK_HAS_BUNDLE;
1777
1778                 track= track->next;
1779         }
1780
1781         if(reconstruction->cameras)
1782                 MEM_freeN(reconstruction->cameras);
1783
1784         reconstruction->cameras= NULL;
1785         reconstruction->camnr= 0;
1786
1787         reconstruction->flag&= ~TRACKING_RECONSTRUCTED;
1788
1789         DAG_id_tag_update(&clip->id, 0);
1790
1791         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
1792         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, NULL);
1793
1794         return OPERATOR_FINISHED;
1795 }
1796
1797 void CLIP_OT_clear_solution(wmOperatorType *ot)
1798 {
1799         /* identifiers */
1800         ot->name= "Clear Solution";
1801         ot->description= "Clear all calculated data";
1802         ot->idname= "CLIP_OT_clear_solution";
1803
1804         /* api callbacks */
1805         ot->exec= clear_solution_exec;
1806         ot->poll= ED_space_clip_poll;
1807
1808         /* flags */
1809         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1810 }
1811
1812 /********************** clear track operator *********************/
1813
1814 static int clear_track_path_exec(bContext *C, wmOperator *op)
1815 {
1816         SpaceClip *sc= CTX_wm_space_clip(C);
1817         MovieClip *clip= ED_space_clip(sc);
1818         MovieTrackingTrack *track;
1819         ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
1820         int action= RNA_enum_get(op->ptr, "action");
1821
1822         track= tracksbase->first;
1823         while(track) {
1824                 if(TRACK_VIEW_SELECTED(sc, track))
1825                         BKE_tracking_clear_path(track, sc->user.framenr, action);
1826
1827                 track= track->next;
1828         }
1829
1830         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
1831
1832         return OPERATOR_FINISHED;
1833 }
1834
1835 void CLIP_OT_clear_track_path(wmOperatorType *ot)
1836 {
1837         static EnumPropertyItem clear_path_actions[] = {
1838                         {TRACK_CLEAR_UPTO, "UPTO", 0, "Clear up-to", "Clear path up to current frame"},
1839                         {TRACK_CLEAR_REMAINED, "REMAINED", 0, "Clear remained", "Clear path at remaining frames (after current)"},
1840                         {TRACK_CLEAR_ALL, "ALL", 0, "Clear all", "Clear the whole path"},
1841                         {0, NULL, 0, NULL, NULL}
1842         };
1843
1844         /* identifiers */
1845         ot->name= "Clear Track Path";
1846         ot->description= "Clear tracks after/before current position or clear the whole track";
1847         ot->idname= "CLIP_OT_clear_track_path";
1848
1849         /* api callbacks */
1850         ot->exec= clear_track_path_exec;
1851         ot->poll= ED_space_clip_poll;
1852
1853         /* flags */
1854         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1855
1856         /* proeprties */
1857         RNA_def_enum(ot->srna, "action", clear_path_actions, TRACK_CLEAR_REMAINED, "Action", "Clear action to execute");
1858 }
1859
1860 /********************** disable markers operator *********************/
1861
1862 static int disable_markers_exec(bContext *C, wmOperator *op)
1863 {
1864         SpaceClip *sc= CTX_wm_space_clip(C);
1865         MovieClip *clip= ED_space_clip(sc);
1866         MovieTracking *tracking= &clip->tracking;
1867         ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
1868         MovieTrackingTrack *track= tracksbase->first;
1869         int action= RNA_enum_get(op->ptr, "action");
1870
1871         while(track) {
1872                 if(TRACK_VIEW_SELECTED(sc, track) && (track->flag&TRACK_LOCKED)==0) {
1873                         MovieTrackingMarker *marker= BKE_tracking_ensure_marker(track, sc->user.framenr);
1874
1875                         if(action==0) marker->flag|= MARKER_DISABLED;
1876                         else if(action==1) marker->flag&= ~MARKER_DISABLED;
1877                         else marker->flag^= MARKER_DISABLED;
1878                 }
1879
1880                 track= track->next;
1881         }
1882
1883         DAG_id_tag_update(&clip->id, 0);
1884
1885         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
1886
1887         return OPERATOR_FINISHED;
1888 }
1889
1890 void CLIP_OT_disable_markers(wmOperatorType *ot)
1891 {
1892         static EnumPropertyItem actions_items[] = {
1893                         {0, "DISABLE", 0, "Disable", "Disable selected markers"},
1894                         {1, "ENABLE", 0, "Enable", "Enable selected markers"},
1895                         {2, "TOGGLE", 0, "Toggle", "Toggle disabled flag for selected markers"},
1896                         {0, NULL, 0, NULL, NULL}
1897         };
1898
1899         /* identifiers */
1900         ot->name= "Disable Markers";
1901         ot->description= "Disable/enable selected markers";
1902         ot->idname= "CLIP_OT_disable_markers";
1903
1904         /* api callbacks */
1905         ot->exec= disable_markers_exec;
1906         ot->poll= ED_space_clip_poll;
1907
1908         /* flags */
1909         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1910
1911         /* properties */
1912         RNA_def_enum(ot->srna, "action", actions_items, 0, "Action", "Disable action to execute");
1913 }
1914
1915 /********************** set origin operator *********************/
1916
1917 static Object *get_camera_with_movieclip(Scene *scene, MovieClip *clip)
1918 {
1919         Object *camera= scene->camera;
1920         Base *base;
1921
1922         if(camera && object_get_movieclip(scene, camera, 0)==clip)
1923                 return camera;
1924
1925         base= scene->base.first;
1926         while(base) {
1927                 if(base->object->type == OB_CAMERA) {
1928                         if(object_get_movieclip(scene, base->object, 0)==clip) {
1929                                 camera= base->object;
1930                                 break;
1931                         }
1932                 }
1933
1934                 base= base->next;
1935         }
1936
1937         return camera;
1938 }
1939
1940 static Object *get_orientation_object(bContext *C)
1941 {
1942         Scene *scene= CTX_data_scene(C);
1943         SpaceClip *sc= CTX_wm_space_clip(C);
1944         MovieClip *clip= ED_space_clip(sc);
1945         MovieTracking *tracking= &clip->tracking;
1946         MovieTrackingObject *tracking_object= BKE_tracking_active_object(tracking);
1947         Object *object= NULL;
1948
1949         if(tracking_object->flag&TRACKING_OBJECT_CAMERA) {
1950                 object= get_camera_with_movieclip(scene, clip);
1951         }
1952         else {
1953                 object= OBACT;
1954         }
1955
1956         if(object && object->parent)
1957                 object= object->parent;
1958
1959         return object;
1960 }
1961
1962 static int set_orientation_poll(bContext *C)
1963 {
1964         if(space_clip_frame_poll(C)) {
1965                 Scene *scene= CTX_data_scene(C);
1966                 SpaceClip *sc= CTX_wm_space_clip(C);
1967                 MovieClip *clip= ED_space_clip(sc);
1968                 MovieTracking *tracking= &clip->tracking;
1969                 MovieTrackingObject *tracking_object= BKE_tracking_active_object(tracking);
1970
1971                 if(tracking_object->flag&TRACKING_OBJECT_CAMERA) {
1972                         return 1;
1973                 }
1974                 else {
1975                         return OBACT != NULL;
1976                 }
1977         }
1978
1979         return 0;
1980 }
1981
1982 static int count_selected_bundles(bContext *C)
1983 {
1984         SpaceClip *sc= CTX_wm_space_clip(C);
1985         MovieClip *clip= ED_space_clip(sc);
1986         ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
1987         MovieTrackingTrack *track;
1988         int tot= 0;
1989
1990         track= tracksbase->first;
1991         while(track) {
1992                 if(TRACK_VIEW_SELECTED(sc, track) && (track->flag&TRACK_HAS_BUNDLE))
1993                         tot++;
1994
1995                 track= track->next;
1996         }
1997
1998         return tot;
1999 }
2000
2001 static void object_solver_inverted_matrix(Scene *scene, Object *ob, float invmat[4][4])
2002 {
2003         bConstraint *con;
2004         int found= 0;
2005
2006         for (con= ob->constraints.first; con; con=con->next) {
2007                 bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
2008
2009                 if(!cti)
2010                         continue;
2011
2012                 if(cti->type==CONSTRAINT_TYPE_OBJECTSOLVER) {
2013                         bObjectSolverConstraint *data= (bObjectSolverConstraint *)con->data;
2014
2015                         if(!found) {
2016                                 Object *cam= data->camera ? data->camera : scene->camera;
2017
2018                                 where_is_object_mat(scene, cam, invmat);
2019                         }
2020
2021                         mult_m4_m4m4(invmat, invmat, data->invmat);
2022
2023                         found= 1;
2024                 }
2025         }
2026
2027         if(found)
2028                 invert_m4(invmat);
2029         else
2030                 unit_m4(invmat);
2031 }
2032
2033 static Object *object_solver_camera(Scene *scene, Object *ob)
2034 {
2035         bConstraint *con;
2036
2037         for (con= ob->constraints.first; con; con=con->next) {
2038                 bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
2039
2040                 if(!cti)
2041                         continue;
2042
2043                 if(cti->type==CONSTRAINT_TYPE_OBJECTSOLVER) {
2044                         bObjectSolverConstraint *data= (bObjectSolverConstraint *)con->data;
2045
2046                         return data->camera ? data->camera : scene->camera;
2047                 }
2048         }
2049
2050         return NULL;
2051 }
2052
2053 static int set_origin_exec(bContext *C, wmOperator *op)
2054 {
2055         SpaceClip *sc= CTX_wm_space_clip(C);
2056         MovieClip *clip= ED_space_clip(sc);
2057         MovieTracking *tracking= &clip->tracking;
2058         MovieTrackingTrack *track;
2059         MovieTrackingObject *tracking_object;
2060         Scene *scene= CTX_data_scene(C);
2061         Object *object;
2062         Object *camera= get_camera_with_movieclip(scene, clip);
2063         ListBase *tracksbase;
2064         float mat[4][4], vec[3], median[3];
2065         int selected_count= count_selected_bundles(C);
2066
2067         if(selected_count==0) {
2068                 BKE_report(op->reports, RPT_ERROR, "At least one track with bundle should be selected to define origin position");
2069
2070                 return OPERATOR_CANCELLED;
2071         }
2072
2073         object= get_orientation_object(C);
2074         if(!object) {
2075                 BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
2076
2077                 return OPERATOR_CANCELLED;
2078         }
2079
2080         tracking_object= BKE_tracking_active_object(tracking);
2081
2082         tracksbase= BKE_tracking_object_tracks(tracking, tracking_object);
2083
2084         track= tracksbase->first;
2085         zero_v3(median);
2086         while(track) {
2087                 if(TRACK_VIEW_SELECTED(sc, track) && (track->flag&TRACK_HAS_BUNDLE)) {
2088                         add_v3_v3(median, track->bundle_pos);
2089                 }
2090
2091                 track= track->next;
2092         }
2093         mul_v3_fl(median, 1.0f/selected_count);
2094
2095         BKE_get_tracking_mat(scene, camera, mat);
2096
2097         mul_v3_m4v3(vec, mat, median);
2098
2099         if(tracking_object->flag&TRACKING_OBJECT_CAMERA) {
2100                 sub_v3_v3(object->loc, vec);
2101         }
2102         else {
2103                 object_solver_inverted_matrix(scene, object, mat);
2104                 mul_v3_m4v3(vec, mat, vec);
2105                 copy_v3_v3(object->loc, vec);
2106         }
2107
2108         DAG_id_tag_update(&clip->id, 0);
2109         DAG_id_tag_update(&object->id, OB_RECALC_OB);
2110
2111         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
2112         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
2113
2114         return OPERATOR_FINISHED;
2115 }
2116
2117 void CLIP_OT_set_origin(wmOperatorType *ot)
2118 {
2119         /* identifiers */
2120         ot->name= "Set Origin";
2121         ot->description= "Set active marker as origin by moving camera (or it's parent if present) in 3D space";
2122         ot->idname= "CLIP_OT_set_origin";
2123
2124         /* api callbacks */
2125         ot->exec= set_origin_exec;
2126         ot->poll= set_orientation_poll;
2127
2128         /* flags */
2129         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2130
2131         /* properties */
2132         RNA_def_boolean(ot->srna, "use_median", 0, "Use Median", "Set origin to median point of selected bundles");
2133 }
2134
2135 /********************** set floor operator *********************/
2136
2137 static void set_axis(Scene *scene,  Object *ob, MovieClip *clip, MovieTrackingObject *tracking_object,
2138                         MovieTrackingTrack *track, char axis)
2139 {
2140         Object *camera= get_camera_with_movieclip(scene, clip);
2141         int is_camera= tracking_object->flag&TRACKING_OBJECT_CAMERA;
2142         int  flip= 0;
2143         float mat[4][4], vec[3], obmat[4][4], dvec[3];
2144
2145         object_to_mat4(ob, obmat);
2146
2147         BKE_get_tracking_mat(scene, camera, mat);
2148         mul_v3_m4v3(vec, mat, track->bundle_pos);
2149         copy_v3_v3(dvec, vec);
2150
2151         if(!is_camera) {
2152                 float imat[4][4];
2153
2154                 object_solver_inverted_matrix(scene, ob, imat);
2155                 mul_v3_m4v3(vec, imat, vec);
2156
2157                 invert_m4_m4(imat, obmat);
2158                 mul_v3_m4v3(dvec, imat, vec);
2159
2160                 sub_v3_v3(vec, obmat[3]);
2161         }
2162
2163         if(len_v2(vec) < 1e-3f)
2164                 return;
2165
2166         unit_m4(mat);
2167
2168         if(axis=='X') {
2169                 if(fabsf(dvec[1])<1e-3f) {
2170                         flip= 1;
2171
2172                         mat[0][0]= -1.0f; mat[0][1]= 0.0f; mat[0][2]= 0.0f;
2173                         mat[1][0]= 0.0f; mat[1][1]= -1.0f; mat[1][2]= 0.0f;
2174                         mat[2][0]= 0.0f; mat[2][1]= 0.0f; mat[2][2]= 1.0f;
2175                 } else {
2176                         copy_v3_v3(mat[0], vec);
2177
2178                         if(is_camera || fabsf(vec[2])<1e-3f) {
2179                                 mat[0][2]= 0.0f;
2180                                 mat[2][0]= 0.0f; mat[2][1]= 0.0f; mat[2][2]= 1.0f;
2181                                 cross_v3_v3v3(mat[1], mat[2], mat[0]);
2182                         }
2183                         else {
2184                                 vec[2]= 0.0f;
2185
2186                                 cross_v3_v3v3(mat[1], mat[0], vec);
2187                                 cross_v3_v3v3(mat[2], mat[0], mat[1]);
2188                         }
2189                 }
2190         } else {
2191                 if(fabsf(dvec[0])<1e-3f) {
2192                         flip= 1;
2193
2194                         mat[0][0]= -1.0f; mat[0][1]= 0.0f; mat[0][2]= 0.0f;
2195                         mat[1][0]= 0.0f; mat[1][1]= -1.0f; mat[1][2]= 0.0f;
2196                         mat[2][0]= 0.0f; mat[2][1]= 0.0f; mat[2][2]= 1.0f;
2197                 } else {
2198                         copy_v3_v3(mat[1], vec);
2199
2200                         if(is_camera || fabsf(vec[2])<1e-3f) {
2201                                 mat[1][2]= 0.0f;
2202                                 mat[2][0]= 0.0f; mat[2][1]= 0.0f; mat[2][2]= 1.0f;
2203                                 cross_v3_v3v3(mat[0], mat[1], mat[2]);
2204                         }
2205                         else {
2206                                 vec[2]= 0.0f;
2207
2208                                 cross_v3_v3v3(mat[0], vec, mat[1]);
2209                                 cross_v3_v3v3(mat[2], mat[0], mat[1]);
2210                         }
2211                 }
2212         }
2213
2214         normalize_v3(mat[0]);
2215         normalize_v3(mat[1]);
2216         normalize_v3(mat[2]);
2217
2218         if(is_camera) {
2219                 invert_m4(mat);
2220
2221                 mult_m4_m4m4(mat, mat, obmat);
2222         }
2223         else {
2224                 if(!flip) {
2225                         float lmat[4][4], ilmat[4][4], rmat[3][3];
2226
2227                         object_rot_to_mat3(ob, rmat);
2228                         invert_m3(rmat);
2229                         mul_m4_m4m3(mat, mat, rmat);
2230
2231                         unit_m4(lmat);
2232                         copy_v3_v3(lmat[3], obmat[3]);
2233                         invert_m4_m4(ilmat, lmat);
2234
2235                         mul_serie_m4(mat, lmat, mat, ilmat, obmat, NULL, NULL, NULL, NULL);
2236                 }
2237                 else {
2238                         mult_m4_m4m4(mat, obmat, mat);
2239                 }
2240         }
2241
2242         object_apply_mat4(ob, mat, 0, 0);
2243 }
2244
2245 static int set_floor_exec(bContext *C, wmOperator *op)
2246 {
2247         SpaceClip *sc= CTX_wm_space_clip(C);
2248         MovieClip *clip= ED_space_clip(sc);
2249         Scene *scene= CTX_data_scene(C);
2250         MovieTracking *tracking= &clip->tracking;
2251         MovieTrackingObject *tracking_object;
2252         MovieTrackingTrack *track, *axis_track= NULL, *act_track;
2253         ListBase *tracksbase;
2254         Object *object;
2255         Object *camera= get_camera_with_movieclip(scene, clip);
2256         int tot= 0;
2257         float vec[3][3], mat[4][4], obmat[4][4], newmat[4][4], orig[3]= {0.0f, 0.0f, 0.0f};
2258         float rot[4][4]={{0.0f, 0.0f, -1.0f, 0.0f},
2259                          {0.0f, 1.0f, 0.0f, 0.0f},
2260                          {1.0f, 0.0f, 0.0f, 0.0f},
2261                          {0.0f, 0.0f, 0.0f, 1.0f}};     /* 90 degrees Y-axis rotation matrix */
2262
2263         if(count_selected_bundles(C)!=3) {
2264                 BKE_report(op->reports, RPT_ERROR, "Three tracks with bundles are needed to orient the floor");
2265
2266                 return OPERATOR_CANCELLED;
2267         }
2268
2269         tracking_object= BKE_tracking_active_object(tracking);
2270         tracksbase= BKE_tracking_object_tracks(tracking, tracking_object);
2271         act_track= BKE_tracking_active_track(tracking);
2272
2273         object= get_orientation_object(C);
2274         if(!object) {
2275                 BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
2276
2277                 return OPERATOR_CANCELLED;
2278         }
2279
2280         BKE_get_tracking_mat(scene, camera, mat);
2281
2282         /* get 3 bundles to use as reference */
2283         track= tracksbase->first;
2284         while(track && tot<3) {
2285                 if(track->flag&TRACK_HAS_BUNDLE && TRACK_VIEW_SELECTED(sc, track)) {
2286                         mul_v3_m4v3(vec[tot], mat, track->bundle_pos);
2287
2288                         if(tot==0 || track==act_track)
2289                                 copy_v3_v3(orig, vec[tot]);
2290                         else
2291                                 axis_track= track;
2292
2293                         tot++;
2294                 }
2295
2296                 track= track->next;
2297         }
2298
2299         sub_v3_v3(vec[1], vec[0]);
2300         sub_v3_v3(vec[2], vec[0]);
2301
2302         /* construct ortho-normal basis */
2303         unit_m4(mat);
2304
2305         cross_v3_v3v3(mat[0], vec[1], vec[2]);
2306         copy_v3_v3(mat[1], vec[1]);
2307         cross_v3_v3v3(mat[2], mat[0], mat[1]);
2308
2309         normalize_v3(mat[0]);
2310         normalize_v3(mat[1]);
2311         normalize_v3(mat[2]);
2312
2313         /* move to origin point */
2314         mat[3][0]= orig[0];
2315         mat[3][1]= orig[1];
2316         mat[3][2]= orig[2];
2317
2318         if(tracking_object->flag&TRACKING_OBJECT_CAMERA) {
2319                 invert_m4(mat);
2320
2321                 object_to_mat4(object, obmat);
2322                 mult_m4_m4m4(mat, mat, obmat);
2323                 mult_m4_m4m4(newmat, rot, mat);
2324                 object_apply_mat4(object, newmat, 0, 0);
2325
2326                 /* make camera have positive z-coordinate */
2327                 if(object->loc[2]<0) {
2328                         invert_m4(rot);
2329                         mult_m4_m4m4(newmat, rot, mat);
2330                         object_apply_mat4(object, newmat, 0, 0);
2331                 }
2332         }
2333         else {
2334                 object_apply_mat4(object, mat, 0, 0);
2335         }
2336
2337         where_is_object(scene, object);
2338         set_axis(scene, object, clip, tracking_object, axis_track, 'X');
2339
2340         DAG_id_tag_update(&clip->id, 0);
2341         DAG_id_tag_update(&object->id, OB_RECALC_OB);
2342
2343         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
2344         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
2345
2346         return OPERATOR_FINISHED;
2347 }
2348
2349 void CLIP_OT_set_floor(wmOperatorType *ot)
2350 {
2351         /* identifiers */
2352         ot->name= "Set Floor";
2353         ot->description= "Set floor based on 3 selected bundles by moving camera (or it's parent if present) in 3D space";
2354         ot->idname= "CLIP_OT_set_floor";
2355
2356         /* api callbacks */
2357         ot->exec= set_floor_exec;
2358         ot->poll= set_orientation_poll;
2359
2360         /* flags */
2361         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2362 }
2363
2364 /********************** set axis operator *********************/
2365
2366 static int set_axis_exec(bContext *C, wmOperator *op)
2367 {
2368         SpaceClip *sc= CTX_wm_space_clip(C);
2369         MovieClip *clip= ED_space_clip(sc);
2370         MovieTracking *tracking= &clip->tracking;
2371         MovieTrackingObject *tracking_object= BKE_tracking_active_object(tracking);
2372         MovieTrackingTrack *track;
2373         Scene *scene= CTX_data_scene(C);
2374         Object *object;
2375         ListBase *tracksbase;
2376         int axis= RNA_enum_get(op->ptr, "axis");
2377
2378         if(count_selected_bundles(C)!=1) {
2379                 BKE_report(op->reports, RPT_ERROR, "Single track with bundle should be selected to define axis");
2380
2381                 return OPERATOR_CANCELLED;
2382         }
2383
2384         object= get_orientation_object(C);
2385         if(!object) {
2386                 BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
2387
2388                 return OPERATOR_CANCELLED;
2389         }
2390
2391         tracksbase= BKE_tracking_object_tracks(tracking, tracking_object);
2392
2393         track=tracksbase->first;
2394         while(track) {
2395                 if(TRACK_VIEW_SELECTED(sc, track))
2396                         break;
2397
2398                 track= track->next;
2399         }
2400
2401         set_axis(scene, object, clip, tracking_object, track, axis==0?'X':'Y');
2402
2403         DAG_id_tag_update(&clip->id, 0);
2404         DAG_id_tag_update(&object->id, OB_RECALC_OB);
2405
2406         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
2407         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
2408
2409         return OPERATOR_FINISHED;
2410 }
2411
2412 void CLIP_OT_set_axis(wmOperatorType *ot)
2413 {
2414         static EnumPropertyItem axis_actions[] = {
2415                         {0, "X", 0, "X", "Align bundle align X axis"},
2416                         {1, "Y", 0, "Y", "Align bundle align Y axis"},
2417                         {0, NULL, 0, NULL, NULL}
2418         };
2419
2420         /* identifiers */
2421         ot->name= "Set Axis";
2422         ot->description= "Set direction of scene axis rotating camera (or it's parent if present) and assuming selected track lies on real axis joining it with the origin";
2423         ot->idname= "CLIP_OT_set_axis";
2424
2425         /* api callbacks */
2426         ot->exec= set_axis_exec;
2427         ot->poll= set_orientation_poll;
2428
2429         /* flags */
2430         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2431
2432         /* properties */
2433         RNA_def_enum(ot->srna, "axis", axis_actions, 0, "Axis", "Axis to use to align bundle along");
2434 }
2435
2436 /********************** set scale operator *********************/
2437
2438 static int do_set_scale(bContext *C, wmOperator *op, int scale_solution)
2439 {
2440         SpaceClip *sc= CTX_wm_space_clip(C);
2441         MovieClip *clip= ED_space_clip(sc);
2442         MovieTracking *tracking= &clip->tracking;
2443         MovieTrackingObject *tracking_object= BKE_tracking_active_object(tracking);
2444         MovieTrackingTrack *track;
2445         Scene *scene= CTX_data_scene(C);
2446         Object *object= NULL;
2447         Object *camera= get_camera_with_movieclip(scene, clip);
2448         ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
2449         int tot= 0;
2450         float vec[2][3], mat[4][4], scale;
2451         float dist= RNA_float_get(op->ptr, "distance");
2452
2453         if(count_selected_bundles(C)!=2) {
2454                 BKE_report(op->reports, RPT_ERROR, "Two tracks with bundles should be selected to set scale");
2455
2456                 return OPERATOR_CANCELLED;
2457         }
2458
2459         object= get_orientation_object(C);
2460         if(!object) {
2461                 BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
2462
2463                 return OPERATOR_CANCELLED;
2464         }
2465
2466         BKE_get_tracking_mat(scene, camera, mat);
2467
2468         track= tracksbase->first;
2469         while(track) {
2470                 if(TRACK_VIEW_SELECTED(sc, track)) {
2471                         mul_v3_m4v3(vec[tot], mat, track->bundle_pos);
2472                         tot++;
2473                 }
2474
2475                 track= track->next;
2476         }
2477
2478         sub_v3_v3(vec[0], vec[1]);
2479
2480         if(len_v3(vec[0])>1e-5f) {
2481                 scale= dist / len_v3(vec[0]);
2482
2483                 if(tracking_object->flag&TRACKING_OBJECT_CAMERA) {
2484                         mul_v3_fl(object->size, scale);
2485                         mul_v3_fl(object->loc, scale);
2486                 }
2487                 else if(!scale_solution){
2488                         Object *solver_camera= object_solver_camera(scene, object);
2489
2490                         object->size[0]= object->size[1]= object->size[2]= 1.0f/scale;
2491
2492                         if(solver_camera) {
2493                                 object->size[0]/= solver_camera->size[0];
2494                                 object->size[1]/= solver_camera->size[1];
2495                                 object->size[2]/= solver_camera->size[2];
2496                         }
2497                 }
2498                 else {
2499                         tracking_object->scale= scale;
2500                 }
2501
2502                 DAG_id_tag_update(&clip->id, 0);
2503
2504                 if(object)
2505                         DAG_id_tag_update(&object->id, OB_RECALC_OB);
2506
2507                 WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
2508                 WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
2509         }
2510
2511         return OPERATOR_FINISHED;
2512 }
2513
2514 static int set_scale_exec(bContext *C, wmOperator *op)
2515 {
2516         return do_set_scale(C, op, 0);
2517 }
2518
2519 static int set_scale_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
2520 {
2521         SpaceClip *sc= CTX_wm_space_clip(C);
2522         MovieClip *clip= ED_space_clip(sc);
2523         float dist= RNA_float_get(op->ptr, "distance");
2524
2525         if(dist==0.0f)
2526                 RNA_float_set(op->ptr, "distance", clip->tracking.settings.dist);
2527
2528         return set_scale_exec(C, op);
2529 }
2530
2531 void CLIP_OT_set_scale(wmOperatorType *ot)
2532 {
2533         /* identifiers */
2534         ot->name= "Set Scale";
2535         ot->description= "Set scale of scene by scaling camera (or it's parent if present)";
2536         ot->idname= "CLIP_OT_set_scale";
2537
2538         /* api callbacks */
2539         ot->exec= set_scale_exec;
2540         ot->invoke= set_scale_invoke;
2541         ot->poll= set_orientation_poll;
2542
2543         /* flags */
2544         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2545
2546         /* properties */
2547         RNA_def_float(ot->srna, "distance", 0.0f, -FLT_MAX, FLT_MAX,
2548                 "Distance", "Distance between selected tracks", -100.0f, 100.0f);
2549 }
2550
2551 /********************** set solution scale operator *********************/
2552
2553 static int set_solution_scale_poll(bContext *C)
2554 {
2555         if(space_clip_frame_poll(C)) {
2556                 SpaceClip *sc= CTX_wm_space_clip(C);
2557                 MovieClip *clip= ED_space_clip(sc);
2558                 MovieTracking *tracking= &clip->tracking;
2559                 MovieTrackingObject *tracking_object= BKE_tracking_active_object(tracking);
2560
2561                 return (tracking_object->flag&TRACKING_OBJECT_CAMERA) == 0;
2562         }
2563
2564         return 0;
2565 }
2566
2567 static int set_solution_scale_exec(bContext *C, wmOperator *op)
2568 {
2569         return do_set_scale(C, op, 1);
2570 }
2571
2572 static int set_solution_scale_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
2573 {
2574         SpaceClip *sc= CTX_wm_space_clip(C);
2575         MovieClip *clip= ED_space_clip(sc);
2576         float dist= RNA_float_get(op->ptr, "distance");
2577
2578         if(dist==0.0f)
2579                 RNA_float_set(op->ptr, "distance", clip->tracking.settings.object_distance);
2580
2581         return set_solution_scale_exec(C, op);
2582 }
2583
2584 void CLIP_OT_set_solution_scale(wmOperatorType *ot)
2585 {
2586         /* identifiers */
2587         ot->name= "Set Solution Scale";
2588         ot->description= "Set object solution scale using distance between two selected tracks";
2589         ot->idname= "CLIP_OT_set_solution_scale";
2590
2591         /* api callbacks */
2592         ot->exec= set_solution_scale_exec;
2593         ot->invoke= set_solution_scale_invoke;
2594         ot->poll= set_solution_scale_poll;
2595
2596         /* flags */
2597         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2598
2599         /* properties */
2600         RNA_def_float(ot->srna, "distance", 0.0f, -FLT_MAX, FLT_MAX,
2601                 "Distance", "Distance between selected tracks", -100.0f, 100.0f);
2602 }
2603
2604 /********************** set principal center operator *********************/
2605
2606 static int set_center_principal_exec(bContext *C, wmOperator *UNUSED(op))
2607 {
2608         SpaceClip *sc= CTX_wm_space_clip(C);
2609         MovieClip *clip= ED_space_clip(sc);
2610         int width, height;
2611
2612         BKE_movieclip_get_size(clip, &sc->user, &width, &height);
2613
2614         if(width==0 || height==0)
2615                 return OPERATOR_CANCELLED;
2616
2617         clip->tracking.camera.principal[0]= ((float)width)/2.0f;
2618         clip->tracking.camera.principal[1]= ((float)height)/2.0f;
2619
2620         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, clip);
2621
2622         return OPERATOR_FINISHED;
2623 }
2624
2625 void CLIP_OT_set_center_principal(wmOperatorType *ot)
2626 {
2627         /* identifiers */
2628         ot->name= "Set Principal to Center";
2629         ot->description= "Set optical center to center of footage";
2630         ot->idname= "CLIP_OT_set_center_principal";
2631
2632         /* api callbacks */
2633         ot->exec= set_center_principal_exec;
2634         ot->poll= ED_space_clip_poll;
2635
2636         /* flags */
2637         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2638 }
2639
2640 /********************** hide tracks operator *********************/
2641
2642 static int hide_tracks_exec(bContext *C, wmOperator *op)
2643 {
2644         SpaceClip *sc= CTX_wm_space_clip(C);
2645         MovieClip *clip= ED_space_clip(sc);
2646         MovieTrackingTrack *track;
2647         MovieTracking *tracking= &clip->tracking;
2648         ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
2649         MovieTrackingTrack *act_track= BKE_tracking_active_track(tracking);
2650         int unselected;
2651
2652         unselected= RNA_boolean_get(op->ptr, "unselected");
2653
2654         track= tracksbase->first;
2655         while(track) {
2656                 if(unselected==0 && TRACK_VIEW_SELECTED(sc, track)) {
2657                         track->flag|= TRACK_HIDDEN;
2658                 } else if(unselected==1 && !TRACK_VIEW_SELECTED(sc, track)) {
2659                         track->flag|= TRACK_HIDDEN;
2660                 }
2661
2662                 track= track->next;
2663         }
2664
2665         if(act_track && act_track->flag&TRACK_HIDDEN)
2666                 clip->tracking.act_track= NULL;
2667
2668         if(unselected==0) {
2669                 /* no selection on screen now, unlock view so it can be scrolled nice again */
2670                 sc->flag&= ~SC_LOCK_SELECTION;
2671         }
2672
2673         WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, NULL);
2674
2675         return OPERATOR_FINISHED;
2676 }
2677
2678 void CLIP_OT_hide_tracks(wmOperatorType *ot)
2679 {
2680         /* identifiers */
2681         ot->name= "Hide Tracks";
2682         ot->description= "Hide selected tracks";
2683         ot->idname= "CLIP_OT_hide_tracks";
2684
2685         /* api callbacks */
2686         ot->exec= hide_tracks_exec;
2687         ot->poll= ED_space_clip_poll;
2688
2689         /* flags */
2690         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2691
2692         /* properties */
2693         RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected tracks");
2694 }
2695
2696 /********************** hide tracks clear operator *********************/
2697
2698 static int hide_tracks_clear_exec(bContext *C, wmOperator *UNUSED(op))
2699 {
2700         SpaceClip *sc= CTX_wm_space_clip(C);
2701         MovieClip *clip= ED_space_clip(sc);
2702         ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
2703         MovieTrackingTrack *track;
2704
2705         track= tracksbase->first;
2706         while(track) {
2707                 track->flag&= ~TRACK_HIDDEN;
2708
2709                 track= track->next;
2710         }
2711
2712         WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, NULL);
2713
2714         return OPERATOR_FINISHED;
2715 }
2716
2717 void CLIP_OT_hide_tracks_clear(wmOperatorType *ot)
2718 {
2719         /* identifiers */
2720         ot->name= "Hide Tracks Clear";
2721         ot->description= "Clear hide selected tracks";
2722         ot->idname= "CLIP_OT_hide_tracks_clear";
2723
2724         /* api callbacks */
2725         ot->exec= hide_tracks_clear_exec;
2726         ot->poll= ED_space_clip_poll;
2727
2728         /* flags */
2729         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2730 }
2731
2732 /********************** detect features operator *********************/
2733
2734 static bGPDlayer *detect_get_layer(MovieClip *clip)
2735 {
2736         bGPDlayer *layer;
2737
2738         if(!clip->gpd)
2739                 return NULL;
2740
2741         layer= clip->gpd->layers.first;
2742         while(layer) {
2743                 if(layer->flag&GP_LAYER_ACTIVE)
2744                         return layer;
2745
2746                 layer= layer->next;
2747         }
2748
2749         return NULL;
2750 }
2751
2752 static int detect_features_exec(bContext *C, wmOperator *op)
2753 {
2754         SpaceClip *sc= CTX_wm_space_clip(C);
2755         MovieClip *clip= ED_space_clip(sc);
2756         int clip_flag= clip->flag&MCLIP_TIMECODE_FLAGS;
2757         ImBuf *ibuf= BKE_movieclip_get_ibuf_flag(clip, &sc->user, clip_flag);
2758         MovieTracking *tracking= &clip->tracking;
2759         ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
2760         MovieTrackingTrack *track= tracksbase->first;
2761         int placement= RNA_enum_get(op->ptr, "placement");
2762         int margin= RNA_int_get(op->ptr, "margin");
2763         int min_trackability= RNA_int_get(op->ptr, "min_trackability");
2764         int min_distance= RNA_int_get(op->ptr, "min_distance");
2765         int place_outside_layer= 0;
2766         bGPDlayer *layer= NULL;
2767
2768         if(placement!=0) {
2769                 layer= detect_get_layer(clip);
2770                 place_outside_layer= placement==2;
2771         }
2772
2773         /* deselect existing tracks */
2774         while(track) {
2775                 track->flag&= ~SELECT;
2776                 track->pat_flag&= ~SELECT;
2777                 track->search_flag&= ~SELECT;
2778
2779                 track= track->next;
2780         }
2781
2782         BKE_tracking_detect_fast(tracking, tracksbase, ibuf, sc->user.framenr, margin,
2783                                 min_trackability, min_distance, layer, place_outside_layer);
2784
2785         IMB_freeImBuf(ibuf);
2786
2787         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, NULL);
2788
2789         return OPERATOR_FINISHED;
2790 }
2791
2792 void CLIP_OT_detect_features(wmOperatorType *ot)
2793 {
2794         static EnumPropertyItem placement_items[] = {
2795                         {0, "FRAME",                    0, "Whole Frame",                       "Place markers across the whole frame"},
2796                         {1, "INSIDE_GPENCIL",   0, "Inside grease pencil",      "Place markers only inside areas outlined with grease pencil"},
2797                         {2, "OUTSIDE_GPENCIL",  0, "Outside grease pencil",     "Place markers only outside areas outlined with grease pencil"},
2798                         {0, NULL, 0, NULL, NULL}
2799         };
2800
2801         /* identifiers */
2802         ot->name= "Detect Features";
2803         ot->description= "Automatically detect features and place markers to track";
2804         ot->idname= "CLIP_OT_detect_features";
2805
2806         /* api callbacks */
2807         ot->exec= detect_features_exec;
2808         ot->poll= space_clip_frame_poll;
2809
2810         /* flags */
2811         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2812
2813         /* properties */
2814         RNA_def_enum(ot->srna, "placement", placement_items, 0, "Placement", "Placement for detected features");
2815         RNA_def_int(ot->srna, "margin", 16, 0, INT_MAX, "Margin", "Only corners further than margin pixels from the image edges are considered", 0, 300);
2816         RNA_def_int(ot->srna, "min_trackability", 16, 0, INT_MAX, "Trackability", "Minimum trackability score to add a corner", 0, 300);
2817         RNA_def_int(ot->srna, "min_distance", 120, 0, INT_MAX, "Distance", "Minimal distance accepted between two corners", 0, 300);
2818 }
2819
2820 /********************** frame jump operator *********************/
2821
2822 static int frame_jump_exec(bContext *C, wmOperator *op)
2823 {
2824         Scene *scene= CTX_data_scene(C);
2825         SpaceClip *sc= CTX_wm_space_clip(C);
2826         MovieClip *clip= ED_space_clip(sc);
2827         MovieTrackingTrack *track;
2828         int pos= RNA_enum_get(op->ptr, "position");
2829         int delta;
2830
2831         if(pos<=1) {    /* jump to path */
2832                 track= BKE_tracking_active_track(&clip->tracking);
2833
2834                 if(!track)
2835                         return OPERATOR_CANCELLED;
2836
2837                 delta= pos == 1 ? 1 : -1;
2838
2839                 while(sc->user.framenr+delta >= SFRA && sc->user.framenr+delta <= EFRA) {
2840                         MovieTrackingMarker *marker= BKE_tracking_exact_marker(track, sc->user.framenr+delta);
2841
2842                         if(!marker || marker->flag&MARKER_DISABLED)
2843                                 break;
2844
2845                         sc->user.framenr+= delta;
2846                 }
2847         }
2848         else {  /* to to failed frame */
2849                 if(clip->tracking.reconstruction.flag&TRACKING_RECONSTRUCTED) {
2850                         int a= sc->user.framenr;
2851                         MovieTracking *tracking= &clip->tracking;
2852                         MovieTrackingObject *object= BKE_tracking_active_object(tracking);
2853
2854                         delta= pos == 3 ? 1 : -1;
2855
2856                         a+= delta;
2857
2858                         while(a+delta >= SFRA && a+delta <= EFRA) {
2859                                 MovieReconstructedCamera *cam;
2860
2861                                 cam= BKE_tracking_get_reconstructed_camera(tracking, object, a);
2862
2863                                 if(!cam) {
2864                                         sc->user.framenr= a;
2865
2866                                         break;
2867                                 }
2868
2869                                 a+= delta;
2870                         }
2871                 }
2872         }
2873
2874         if(CFRA!=sc->user.framenr) {
2875                 CFRA= sc->user.framenr;
2876                 sound_seek_scene(CTX_data_main(C), CTX_data_scene(C));
2877
2878                 WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
2879         }
2880
2881         WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, NULL);
2882
2883         return OPERATOR_FINISHED;
2884 }
2885
2886 void CLIP_OT_frame_jump(wmOperatorType *ot)
2887 {
2888         static EnumPropertyItem position_items[] = {
2889                         {0, "PATHSTART",        0, "Path Start",                "Jump to start of current path"},
2890                         {1, "PATHEND",          0, "Path End",                  "Jump to end of current path"},
2891                         {2, "FAILEDPREV",       0, "Previous Failed",   "Jump to previous failed frame"},
2892                         {2, "FAILNEXT",         0, "Next Failed",               "Jump to next failed frame"},
2893                         {0, NULL, 0, NULL, NULL}
2894         };
2895
2896         /* identifiers */
2897         ot->name= "Jump to Frame";
2898         ot->description= "Jump to special frame";
2899         ot->idname= "CLIP_OT_frame_jump";
2900
2901         /* api callbacks */
2902         ot->exec= frame_jump_exec;
2903         ot->poll= space_clip_frame_poll;
2904
2905         /* flags */
2906         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2907
2908         /* properties */
2909         RNA_def_enum(ot->srna, "position", position_items, 0, "Position", "Position to jumo to");
2910 }
2911
2912 /********************** join tracks operator *********************/
2913
2914 static int join_tracks_exec(bContext *C, wmOperator *op)
2915 {
2916         SpaceClip *sc= CTX_wm_space_clip(C);
2917         MovieClip *clip= ED_space_clip(sc);
2918         MovieTracking *tracking= &clip->tracking;
2919         ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
2920         MovieTrackingTrack *act_track, *track, *next;
2921
2922         act_track= BKE_tracking_active_track(tracking);
2923
2924         if(!act_track) {
2925                 BKE_report(op->reports, RPT_ERROR, "No active track to join to");
2926                 return OPERATOR_CANCELLED;
2927         }
2928
2929         track= tracksbase->first;
2930         while(track) {
2931                 if(TRACK_VIEW_SELECTED(sc, track) && track!=act_track) {
2932                         if(!BKE_tracking_test_join_tracks(act_track, track)) {
2933                                 BKE_report(op->reports, RPT_ERROR, "Some selected tracks have got keyframed markers to the same frame");
2934                                 return OPERATOR_CANCELLED;
2935                         }
2936                 }
2937
2938                 track= track->next;
2939         }
2940
2941         track= tracksbase->first;
2942         while(track) {
2943                 next= track->next;
2944
2945                 if(TRACK_VIEW_SELECTED(sc, track) && track!=act_track) {
2946                         BKE_tracking_join_tracks(act_track, track);
2947
2948                         BKE_tracking_free_track(track);
2949                         BLI_freelinkN(tracksbase, track);
2950                 }
2951
2952                 track= next;
2953         }
2954
2955         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, clip);
2956
2957         return OPERATOR_FINISHED;
2958 }
2959
2960 void CLIP_OT_join_tracks(wmOperatorType *ot)
2961 {
2962         /* identifiers */
2963         ot->name= "Join Tracks";
2964         ot->description= "Join selected tracks";
2965         ot->idname= "CLIP_OT_join_tracks";
2966
2967         /* api callbacks */
2968         ot->exec= join_tracks_exec;
2969         ot->poll= space_clip_frame_poll;
2970
2971         /* flags */
2972         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2973 }
2974
2975 /********************** lock tracks operator *********************/
2976
2977 static int lock_tracks_exec(bContext *C, wmOperator *op)
2978 {
2979         SpaceClip *sc= CTX_wm_space_clip(C);
2980         MovieClip *clip= ED_space_clip(sc);
2981         MovieTracking *tracking= &clip->tracking;
2982         ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
2983         MovieTrackingTrack *track= tracksbase->first;
2984         int action= RNA_enum_get(op->ptr, "action");
2985
2986         while(track) {
2987                 if(TRACK_VIEW_SELECTED(sc, track)) {
2988                         if(action==0) track->flag|= TRACK_LOCKED;
2989                         else if(action==1) track->flag&= ~TRACK_LOCKED;
2990                         else track->flag^= TRACK_LOCKED;
2991                 }
2992
2993                 track= track->next;
2994         }
2995
2996         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
2997
2998         return OPERATOR_FINISHED;
2999 }
3000
3001 void CLIP_OT_lock_tracks(wmOperatorType *ot)
3002 {
3003         static EnumPropertyItem actions_items[] = {
3004                         {0, "LOCK", 0, "Lock", "Lock selected tracks"},
3005                         {1, "UNLOCK", 0, "Unlock", "Unlock selected tracks"},
3006                         {2, "TOGGLE", 0, "Toggle", "Toggle locked flag for selected tracks"},
3007                         {0, NULL, 0, NULL, NULL}
3008         };
3009
3010         /* identifiers */
3011         ot->name= "Lock Tracks";
3012         ot->description= "Lock/unlock selected tracks";
3013         ot->idname= "CLIP_OT_lock_tracks";
3014
3015         /* api callbacks */
3016         ot->exec= lock_tracks_exec;
3017         ot->poll= ED_space_clip_poll;
3018
3019         /* flags */
3020         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
3021
3022         /* properties */
3023         RNA_def_enum(ot->srna, "action", actions_items, 0, "Action", "Lock action to execute");
3024 }
3025
3026 /********************** track copy color operator *********************/
3027
3028 static int track_copy_color_exec(bContext *C, wmOperator *UNUSED(op))
3029 {
3030         SpaceClip *sc= CTX_wm_space_clip(C);
3031         MovieClip *clip= ED_space_clip(sc);
3032         MovieTracking *tracking= &clip->tracking;
3033         ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
3034         MovieTrackingTrack *track, *act_track= BKE_tracking_active_track(tracking);
3035
3036         if(!act_track)
3037                 return OPERATOR_CANCELLED;
3038
3039         track= tracksbase->first;
3040         while(track) {
3041                 if(TRACK_VIEW_SELECTED(sc, track) && track!=act_track) {
3042                         track->flag&= ~TRACK_CUSTOMCOLOR;
3043
3044                         if(act_track->flag&TRACK_CUSTOMCOLOR) {
3045                                 copy_v3_v3(track->color, act_track->color);
3046                                 track->flag|= TRACK_CUSTOMCOLOR;
3047                         }
3048                 }
3049
3050                 track= track->next;
3051         }
3052
3053         WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, clip);
3054
3055         return OPERATOR_FINISHED;
3056 }
3057
3058 void CLIP_OT_track_copy_color(wmOperatorType *ot)
3059 {
3060         /* identifiers */
3061         ot->name= "Copy Color";
3062         ot->description= "Copy color to all selected tracks";
3063         ot->idname= "CLIP_OT_track_copy_color";
3064
3065         /* api callbacks */
3066         ot->exec= track_copy_color_exec;
3067         ot->poll= ED_space_clip_poll;
3068
3069         /* flags */
3070         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
3071 }
3072
3073 /********************** add 2d stabilization tracks operator *********************/
3074
3075 static int stabilize_2d_add_exec(bContext *C, wmOperator *UNUSED(op))
3076 {
3077         SpaceClip *sc= CTX_wm_space_clip(C);
3078         MovieClip *clip= ED_space_clip(sc);
3079         MovieTracking *tracking= &clip->tracking;
3080         ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
3081         MovieTrackingTrack *track;
3082         MovieTrackingStabilization *stab= &tracking->stabilization;
3083         int update= 0;
3084
3085         track= tracksbase->first;
3086         while(track) {
3087                 if(TRACK_VIEW_SELECTED(sc, track) && (track->flag&TRACK_USE_2D_STAB)==0) {
3088                         track->flag|= TRACK_USE_2D_STAB;
3089                         stab->tot_track++;
3090
3091                         update= 1;
3092                 }
3093
3094                 track= track->next;
3095         }
3096
3097         if(update) {
3098                 stab->ok= 0;
3099
3100                 DAG_id_tag_update(&clip->id, 0);
3101                 WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, clip);
3102         }
3103
3104         return OPERATOR_FINISHED;
3105 }
3106
3107 void CLIP_OT_stabilize_2d_add(wmOperatorType *ot)
3108 {
3109         /* identifiers */
3110         ot->name= "Add Stabilization Tracks";
3111         ot->description= "Add selected tracks to 2D stabilization tool";
3112         ot->idname= "CLIP_OT_stabilize_2d_add";
3113
3114         /* api callbacks */
3115         ot->exec= stabilize_2d_add_exec;
3116         ot->poll= ED_space_clip_poll;
3117
3118         /* flags */
3119         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
3120 }
3121
3122 /********************** remove 2d stabilization tracks operator *********************/
3123
3124 static int stabilize_2d_remove_exec(bContext *C, wmOperator *UNUSED(op))
3125 {
3126         SpaceClip *sc= CTX_wm_space_clip(C);
3127         MovieClip *clip= ED_space_clip(sc);
3128         MovieTracking *tracking= &clip->tracking;
3129         MovieTrackingStabilization *stab= &tracking->stabilization;
3130         ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
3131         MovieTrackingTrack *track;
3132         int a= 0, update= 0;
3133
3134         track= tracksbase->first;
3135         while(track) {
3136                 if(track->flag&TRACK_USE_2D_STAB) {
3137                         if(a==stab->act_track) {
3138                                 track->flag&= ~TRACK_USE_2D_STAB;
3139
3140                                 stab->act_track--;
3141                                 stab->tot_track--;
3142
3143                                 if(stab->act_track<0)
3144                                         stab->act_track= 0;
3145
3146                                 update= 1;
3147
3148                                 break;
3149                         }
3150
3151                         a++;
3152                 }
3153
3154                 track= track->next;
3155         }
3156
3157         if(update) {
3158                 stab->ok= 0;
3159
3160                 DAG_id_tag_update(&clip->id, 0);
3161                 WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, clip);
3162         }
3163
3164         return OPERATOR_FINISHED;
3165 }
3166
3167 void CLIP_OT_stabilize_2d_remove(wmOperatorType *ot)
3168 {
3169         /* identifiers */
3170         ot->name= "Remove Stabilization Track";
3171         ot->description= "Remove selected track from stabilization";
3172         ot->idname= "CLIP_OT_stabilize_2d_remove";
3173
3174         /* api callbacks */
3175         ot->exec= stabilize_2d_remove_exec;
3176         ot->poll= ED_space_clip_poll;
3177
3178         /* flags */
3179         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
3180 }
3181
3182 /********************** select 2d stabilization tracks operator *********************/
3183
3184 static int stabilize_2d_select_exec(bContext *C, wmOperator *UNUSED(op))
3185 {
3186         SpaceClip *sc= CTX_wm_space_clip(C);
3187         MovieClip *clip= ED_space_clip(sc);
3188         MovieTracking *tracking= &clip->tracking;
3189         ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
3190         MovieTrackingTrack *track;
3191         int update= 0;
3192
3193         track= tracksbase->first;
3194         while(track) {
3195                 if(track->flag&TRACK_USE_2D_STAB) {
3196                         BKE_tracking_track_flag(track, TRACK_AREA_ALL, SELECT, 0);
3197
3198                         update= 1;
3199                 }
3200
3201                 track= track->next;
3202         }
3203
3204         if(update)
3205                 WM_event_add_notifier(C, NC_MOVIECLIP|ND_SELECT, clip);
3206
3207         return OPERATOR_FINISHED;
3208 }
3209
3210 void CLIP_OT_stabilize_2d_select(wmOperatorType *ot)
3211 {
3212         /* identifiers */
3213         ot->name= "Select Stabilization Tracks";
3214         ot->description= "Select track which are used for stabilization";
3215         ot->idname= "CLIP_OT_stabilize_2d_select";
3216
3217         /* api callbacks */
3218         ot->exec= stabilize_2d_select_exec;
3219         ot->poll= ED_space_clip_poll;
3220
3221         /* flags */
3222         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
3223 }
3224
3225 /********************** set 2d stabilization rotation track operator *********************/
3226
3227 static int stabilize_2d_set_rotation_exec(bContext *C, wmOperator *UNUSED(op))
3228 {
3229         SpaceClip *sc= CTX_wm_space_clip(C);
3230         MovieClip *clip= ED_space_clip(sc);
3231         MovieTracking *tracking= &clip->tracking;
3232         MovieTrackingTrack *act_track= BKE_tracking_active_track(tracking);
3233
3234         if(act_track) {
3235                 MovieTrackingStabilization *stab= &tracking->stabilization;
3236
3237                 stab->rot_track= act_track;
3238                 stab->ok= 0;
3239
3240                 DAG_id_tag_update(&clip->id, 0);
3241                 WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, clip);
3242         }
3243
3244         return OPERATOR_FINISHED;
3245 }
3246
3247 void CLIP_OT_stabilize_2d_set_rotation(wmOperatorType *ot)
3248 {
3249         /* identifiers */
3250         ot->name= "Set Rotation Track";
3251         ot->description= "Use active track to compensate rotation when doing 2D stabilization";
3252         ot->idname= "CLIP_OT_stabilize_2d_set_rotation";
3253
3254         /* api callbacks */
3255         ot->exec= stabilize_2d_set_rotation_exec;
3256         ot->poll= ED_space_clip_poll;
3257
3258         /* flags */
3259         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
3260 }
3261
3262 /********************** clean tracks operator *********************/
3263
3264 static int is_track_clean(MovieTrackingTrack *track, int frames, int del)
3265 {
3266         int ok= 1, a, prev= -1, count= 0;
3267         MovieTrackingMarker *markers= track->markers, *new_markers= NULL;
3268         int start_disabled= 0;
3269         int markersnr= track->markersnr;
3270
3271         if(del)
3272                 new_markers= MEM_callocN(markersnr*sizeof(MovieTrackingMarker), "track cleaned markers");
3273
3274         for(a= 0; a<markersnr; a++) {
3275                 int end= 0;