4 * ***** BEGIN GPL LICENSE BLOCK *****
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 * The Original Code is Copyright (C) 2011 Blender Foundation.
21 * All rights reserved.
24 * Contributor(s): Blender Foundation,
27 * ***** END GPL LICENSE BLOCK *****
30 #include "MEM_guardedalloc.h"
32 #include "DNA_camera_types.h"
33 #include "DNA_movieclip_types.h"
34 #include "DNA_object_types.h" /* SELECT */
35 #include "DNA_scene_types.h"
37 #include "BLI_utildefines.h"
39 #include "BLI_listbase.h"
41 #include "BLI_blenlib.h"
44 #include "BKE_context.h"
45 #include "BKE_movieclip.h"
46 #include "BKE_tracking.h"
47 #include "BKE_global.h"
48 #include "BKE_depsgraph.h"
49 #include "BKE_object.h"
50 #include "BKE_report.h"
51 #include "BKE_scene.h"
52 #include "BKE_sound.h"
57 #include "ED_screen.h"
59 #include "ED_keyframing.h"
61 #include "IMB_imbuf_types.h"
62 #include "IMB_imbuf.h"
64 #include "UI_interface.h"
66 #include "RNA_access.h"
67 #include "RNA_define.h"
71 #include "UI_view2d.h"
73 #include "clip_intern.h" // own include
75 /** \file blender/editors/space_clip/tracking_ops.c
79 static int space_clip_tracking_poll(bContext *C)
81 SpaceClip *sc= CTX_wm_space_clip(C);
89 static int space_clip_frame_poll(bContext *C)
91 SpaceClip *sc= CTX_wm_space_clip(C);
94 MovieClip *clip= ED_space_clip(sc);
97 return BKE_movieclip_has_frame(clip, &sc->user);
103 static int space_clip_frame_camera_poll(bContext *C)
105 Scene *scene= CTX_data_scene(C);
107 if(space_clip_frame_poll(C)) {
108 return scene->camera != NULL;
114 static int space_clip_camera_poll(bContext *C)
116 SpaceClip *sc= CTX_wm_space_clip(C);
117 Scene *scene= CTX_data_scene(C);
119 if(sc && sc->clip && scene->camera)
125 /********************** add marker operator *********************/
127 static void add_marker(SpaceClip *sc, float x, float y)
129 MovieClip *clip= ED_space_clip(sc);
130 MovieTrackingTrack *track;
131 int width, height, sel= 0;
133 ED_space_clip_size(sc, &width, &height);
135 track= BKE_tracking_add_track(&clip->tracking, x, y, sc->user.framenr, width, height);
137 sel= TRACK_AREA_POINT;
138 if(sc->flag&SC_SHOW_MARKER_PATTERN) sel|= TRACK_AREA_PAT;
139 if(sc->flag&SC_SHOW_MARKER_SEARCH) sel|= TRACK_AREA_SEARCH;
141 BKE_movieclip_select_track(clip, track, sel, 0);
142 BKE_movieclip_set_selection(clip, MCLIP_SEL_TRACK, track);
145 static int add_marker_exec(bContext *C, wmOperator *op)
147 SpaceClip *sc= CTX_wm_space_clip(C);
148 MovieClip *clip= ED_space_clip(sc);
152 ED_space_clip_size(sc, &width, &height);
153 if(!width || !height)
154 return OPERATOR_CANCELLED;
156 RNA_float_get_array(op->ptr, "location", pos);
158 add_marker(sc, pos[0], pos[1]);
160 WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, clip);
162 return OPERATOR_FINISHED;
165 static void point_stable_pos(bContext *C, float x, float y, float *xr, float *yr)
167 ARegion *ar= CTX_wm_region(C);
168 SpaceClip *sc= CTX_wm_space_clip(C);
169 int sx, sy, width, height;
170 float zoomx, zoomy, pos[3]={0.f, 0.f, 0.f}, imat[4][4];
172 ED_space_clip_zoom(sc, ar, &zoomx, &zoomy);
173 ED_space_clip_size(sc, &width, &height);
175 UI_view2d_to_region_no_clip(&ar->v2d, 0.0f, 0.0f, &sx, &sy);
177 pos[0]= (x-sx)/zoomx;
178 pos[1]= (y-sy)/zoomy;
180 invert_m4_m4(imat, sc->stabmat);
181 mul_v3_m4v3(pos, imat, pos);
187 static void mouse_pos(bContext *C, wmEvent *event, float co[2])
189 point_stable_pos(C, event->mval[0], event->mval[1], &co[0], &co[1]);
192 static int add_marker_invoke(bContext *C, wmOperator *op, wmEvent *event)
196 mouse_pos(C, event, co);
198 RNA_float_set_array(op->ptr, "location", co);
200 return add_marker_exec(C, op);
203 void CLIP_OT_add_marker(wmOperatorType *ot)
206 ot->name= "Add Marker";
207 ot->idname= "CLIP_OT_add_marker";
208 ot->description= "Place new marker at specified location";
211 ot->invoke= add_marker_invoke;
212 ot->exec= add_marker_exec;
213 ot->poll= space_clip_frame_poll;
216 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
219 RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MIN, FLT_MAX,
220 "Location", "Location of marker on frame.", -1.f, 1.f);
223 /********************** delete track operator *********************/
225 static int delete_track_exec(bContext *C, wmOperator *UNUSED(op))
227 SpaceClip *sc= CTX_wm_space_clip(C);
228 MovieClip *clip= ED_space_clip(sc);
229 MovieTrackingTrack *track= clip->tracking.tracks.first, *next;
235 if(TRACK_SELECTED(track)) {
236 if(track->flag&TRACK_HAS_BUNDLE)
239 BKE_tracking_free_track(track);
240 BLI_freelinkN(&clip->tracking.tracks, track);
246 BKE_movieclip_set_selection(clip, MCLIP_SEL_NONE, NULL);
247 WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, clip);
250 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, NULL);
252 return OPERATOR_FINISHED;
255 void CLIP_OT_delete_track(wmOperatorType *ot)
258 ot->name= "Delete Track";
259 ot->idname= "CLIP_OT_delete_track";
260 ot->description= "Delete selected tracks";
263 ot->invoke= WM_operator_confirm;
264 ot->exec= delete_track_exec;
265 ot->poll= space_clip_tracking_poll;
268 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
271 /********************** delete marker operator *********************/
273 static int delete_marker_exec(bContext *C, wmOperator *UNUSED(op))
275 SpaceClip *sc= CTX_wm_space_clip(C);
276 MovieClip *clip= ED_space_clip(sc);
277 MovieTrackingTrack *track= clip->tracking.tracks.first, *next;
278 int framenr= sc->user.framenr, sel_type;
281 BKE_movieclip_last_selection(clip, &sel_type, &sel);
286 if(TRACK_SELECTED(track)) {
287 MovieTrackingMarker *marker= BKE_tracking_exact_marker(track, framenr);
290 if(track->markersnr==1) {
291 if(sel_type==MCLIP_SEL_TRACK && sel==track)
292 BKE_movieclip_set_selection(clip, MCLIP_SEL_NONE, NULL);
294 BKE_tracking_free_track(track);
295 BLI_freelinkN(&clip->tracking.tracks, track);
297 BKE_tracking_delete_marker(track, framenr);
305 WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, clip);
307 return OPERATOR_FINISHED;
310 void CLIP_OT_delete_marker(wmOperatorType *ot)
313 ot->name= "Delete Marker";
314 ot->idname= "CLIP_OT_delete_marker";
315 ot->description= "Delete marker for current frame from selected tracks";
318 ot->invoke= WM_operator_confirm;
319 ot->exec= delete_marker_exec;
320 ot->poll= space_clip_tracking_poll;
323 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
326 /********************** slide marker operator *********************/
328 #define SLIDE_ACTION_POS 0
329 #define SLIDE_ACTION_SIZE 1
330 #define SLIDE_ACTION_OFFSET 2
334 MovieTrackingTrack *track;
335 MovieTrackingMarker *marker;
339 float *min, *max, *pos, *offset;
340 float smin[2], smax[2], spos[2], soff[2];
345 static SlideMarkerData *create_slide_marker_data(SpaceClip *sc, MovieTrackingTrack *track,
346 MovieTrackingMarker *marker, wmEvent *event, int area, int action, int width, int height)
348 SlideMarkerData *data= MEM_callocN(sizeof(SlideMarkerData), "slide marker data");
350 marker= BKE_tracking_ensure_marker(track, sc->user.framenr);
353 data->action= action;
355 data->marker= marker;
357 if(area==TRACK_AREA_POINT) {
358 data->pos= marker->pos;
359 data->offset= track->offset;
360 copy_v2_v2(data->spos, marker->pos);
361 copy_v2_v2(data->soff, track->offset);
362 } else if(area==TRACK_AREA_PAT) {
363 if(action==SLIDE_ACTION_SIZE) {
364 data->min= track->pat_min;
365 data->max= track->pat_max;
367 data->pos= marker->pos;
368 data->offset= track->offset;
369 copy_v2_v2(data->spos, marker->pos);
370 copy_v2_v2(data->soff, track->offset);
372 } else if(area==TRACK_AREA_SEARCH) {
373 data->min= track->search_min;
374 data->max= track->search_max;
377 if(area==TRACK_AREA_SEARCH || (area==TRACK_AREA_PAT && action!=SLIDE_ACTION_OFFSET)) {
378 copy_v2_v2(data->smin, data->min);
379 copy_v2_v2(data->smax, data->max);
382 data->mval[0]= event->mval[0];
383 data->mval[1]= event->mval[1];
386 data->height= height;
388 if(action==SLIDE_ACTION_SIZE)
394 /* corner = 0: right-bottom corner,
395 corner = 1: left-top corner */
396 static int mouse_on_corner(SpaceClip *sc, MovieTrackingTrack *track, MovieTrackingMarker *marker,
397 int area, float co[2], int corner, int width, int height)
401 float min[2], max[2];
402 float crn[2], dx, dy, tdx, tdy;
404 if(area==TRACK_AREA_SEARCH) {
405 copy_v2_v2(min, track->search_min);
406 copy_v2_v2(max, track->search_max);
408 copy_v2_v2(min, track->pat_min);
409 copy_v2_v2(max, track->pat_max);
412 dx= size/width/sc->zoom;
413 dy= size/height/sc->zoom;
415 tdx= 5.0f/width/sc->zoom;
416 tdy= 5.0f/height/sc->zoom;
418 dx= MIN2(dx, (max[0]-min[0])/6.f) + tdx;
419 dy= MIN2(dy, (max[1]-min[1])/6.f) + tdy;
422 crn[0]= marker->pos[0]+max[0];
423 crn[1]= marker->pos[1]+min[1];
425 inside= co[0]>=crn[0]-dx && co[0]<=crn[0]+tdx && co[1]>=crn[1]-tdy && co[1]<=crn[1]+dy;
427 crn[0]= marker->pos[0]+min[0];
428 crn[1]= marker->pos[1]+max[1];
430 inside= co[0]>=crn[0]-dx && co[0]<=crn[0]+dx && co[1]>=crn[1]-dy && co[1]<=crn[1]+dy;
436 static int mouse_on_offset(SpaceClip *sc, MovieTrackingTrack *track, MovieTrackingMarker *marker,
437 float co[2], int width, int height)
439 float pos[2], dx, dy;
441 add_v2_v2v2(pos, marker->pos, track->offset);
443 dx= 12.f/width/sc->zoom;
444 dy= 12.f/height/sc->zoom;
446 dx=MIN2(dx, (track->pat_max[0]-track->pat_min[0])/3);
447 dy=MIN2(dy, (track->pat_max[1]-track->pat_min[1])/3);
449 return co[0]>=pos[0]-dx && co[0]<=pos[0]+dx && co[1]>=pos[1]-dy && co[1]<=pos[1]+dy;
452 static void hide_cursor(bContext *C)
454 wmWindow *win= CTX_wm_window(C);
456 WM_cursor_set(win, CURSOR_NONE);
459 static void show_cursor(bContext *C)
461 wmWindow *win= CTX_wm_window(C);
463 WM_cursor_set(win, CURSOR_STD);
466 static void *slide_marker_customdata(bContext *C, wmEvent *event)
468 SpaceClip *sc= CTX_wm_space_clip(C);
469 MovieClip *clip= ED_space_clip(sc);
470 MovieTrackingTrack *track;
473 void *customdata= NULL;
475 ED_space_clip_size(sc, &width, &height);
477 if(width==0 || height==0)
480 mouse_pos(C, event, co);
482 track= clip->tracking.tracks.first;
484 if(TRACK_SELECTED(track) && (track->flag&TRACK_LOCKED)==0) {
485 MovieTrackingMarker *marker= BKE_tracking_get_marker(track, sc->user.framenr);
487 if((marker->flag&MARKER_DISABLED)==0) {
488 if(sc->flag&SC_SHOW_MARKER_SEARCH) {
489 if(mouse_on_corner(sc, track, marker, TRACK_AREA_SEARCH, co, 1, width, height))
490 customdata= create_slide_marker_data(sc, track, marker, event, TRACK_AREA_SEARCH, SLIDE_ACTION_OFFSET, width, height);
491 else if(mouse_on_corner(sc, track, marker, TRACK_AREA_SEARCH, co, 0, width, height))
492 customdata= create_slide_marker_data(sc, track, marker, event, TRACK_AREA_SEARCH, SLIDE_ACTION_SIZE, width, height);
495 if(!customdata && sc->flag&SC_SHOW_MARKER_PATTERN) {
496 if(mouse_on_corner(sc, track, marker, TRACK_AREA_PAT, co, 1, width, height))
497 customdata= create_slide_marker_data(sc, track, marker, event, TRACK_AREA_PAT, SLIDE_ACTION_OFFSET, width, height);
499 if(!customdata && mouse_on_corner(sc, track, marker, TRACK_AREA_PAT, co, 0, width, height))
500 customdata= create_slide_marker_data(sc, track, marker, event, TRACK_AREA_PAT, SLIDE_ACTION_SIZE, width, height);
504 if(mouse_on_offset(sc, track, marker, co, width, height))
505 customdata= create_slide_marker_data(sc, track, marker, event, TRACK_AREA_POINT, SLIDE_ACTION_POS, width, height);
518 static int slide_marker_invoke(bContext *C, wmOperator *op, wmEvent *event)
520 op->customdata= slide_marker_customdata(C, event);
524 WM_event_add_modal_handler(C, op);
526 return OPERATOR_RUNNING_MODAL;
529 return OPERATOR_CANCELLED;
532 static void cancel_mouse_slide(SlideMarkerData *data)
535 if(data->area == TRACK_AREA_POINT) {
536 if(data->action==SLIDE_ACTION_OFFSET)
537 copy_v2_v2(data->offset, data->soff);
539 copy_v2_v2(data->pos, data->spos);
541 if(data->action==SLIDE_ACTION_SIZE) {
542 copy_v2_v2(data->min, data->smin);
543 copy_v2_v2(data->max, data->smax);
548 static int slide_marker_modal(bContext *C, wmOperator *op, wmEvent *event)
550 SpaceClip *sc= CTX_wm_space_clip(C);
551 SlideMarkerData *data= (SlideMarkerData *)op->customdata;
552 float dx, dy, mdelta[2];
554 switch(event->type) {
559 if(data->action==SLIDE_ACTION_SIZE)
560 if(ELEM(event->type, LEFTCTRLKEY, RIGHTCTRLKEY))
561 data->lock= event->val==KM_RELEASE;
563 if(ELEM(event->type, LEFTSHIFTKEY, RIGHTSHIFTKEY))
564 data->accurate= event->val==KM_PRESS;
566 /* no break! update area size */
569 mdelta[0]= event->mval[0]-data->mval[0];
570 mdelta[1]= event->mval[1]-data->mval[1];
572 dx= mdelta[0]/data->width/sc->zoom;
574 if(data->lock) dy= -dx/data->height*data->width;
575 else dy= mdelta[1]/data->height/sc->zoom;
582 if(data->area==TRACK_AREA_POINT) {
583 if(data->action==SLIDE_ACTION_OFFSET) {
584 data->offset[0]= data->soff[0]+dx;
585 data->offset[1]= data->soff[1]+dy;
587 data->pos[0]= data->spos[0]+dx;
588 data->pos[1]= data->spos[1]+dy;
590 data->marker->flag&= ~MARKER_TRACKED;
593 WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
594 DAG_id_tag_update(&sc->clip->id, 0);
596 if(data->action==SLIDE_ACTION_SIZE) {
597 data->min[0]= data->smin[0]-dx;
598 data->max[0]= data->smax[0]+dx;
600 data->min[1]= data->smin[1]+dy;
601 data->max[1]= data->smax[1]-dy;
603 if(data->area==TRACK_AREA_SEARCH) BKE_tracking_clamp_track(data->track, CLAMP_SEARCH_DIM);
604 else BKE_tracking_clamp_track(data->track, CLAMP_PAT_DIM);
608 if(data->area==TRACK_AREA_SEARCH) {
609 add_v2_v2v2(data->min, data->smin, d);
610 add_v2_v2v2(data->max, data->smax, d);
612 add_v2_v2v2(data->pos, data->spos, d);
613 add_v2_v2v2(data->pos, data->spos, d);
615 sub_v2_v2v2(data->offset, data->soff, d);
618 if(data->area==TRACK_AREA_SEARCH)
619 BKE_tracking_clamp_track(data->track, CLAMP_SEARCH_POS);
623 WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, NULL);
628 if(event->val==KM_RELEASE) {
629 MEM_freeN(op->customdata);
633 return OPERATOR_FINISHED;
639 cancel_mouse_slide(op->customdata);
641 MEM_freeN(op->customdata);
645 WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, NULL);
647 return OPERATOR_CANCELLED;
650 return OPERATOR_RUNNING_MODAL;
653 void CLIP_OT_slide_marker(wmOperatorType *ot)
656 ot->name= "Slide Marker";
657 ot->description= "Slide marker areas";
658 ot->idname= "CLIP_OT_slide_marker";
661 //ot->exec= slide_marker_exec;
662 ot->poll= space_clip_frame_poll;
663 ot->invoke= slide_marker_invoke;
664 ot->modal= slide_marker_modal;
667 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
670 RNA_def_float_vector(ot->srna, "offset", 2, NULL, -FLT_MAX, FLT_MAX,
671 "Offset", "Offset in floating point units, 1.0 is the width and height of the image.", -FLT_MAX, FLT_MAX);
674 /********************** mouse select operator *********************/
676 static int mouse_on_side(float co[2], float x1, float y1, float x2, float y2, float epsx, float epsy)
678 if(x1>x2) SWAP(float, x1, x2);
679 if(y1>y2) SWAP(float, y1, y2);
681 return (co[0]>=x1-epsx && co[0]<=x2+epsx) && (co[1]>=y1-epsy && co[1]<=y2+epsy);
684 static int mouse_on_rect(float co[2], float pos[2], float min[2], float max[2], float epsx, float epsy)
686 return mouse_on_side(co, pos[0]+min[0], pos[1]+min[1], pos[0]+max[0], pos[1]+min[1], epsx, epsy) ||
687 mouse_on_side(co, pos[0]+min[0], pos[1]+min[1], pos[0]+min[0], pos[1]+max[1], epsx, epsy) ||
688 mouse_on_side(co, pos[0]+min[0], pos[1]+max[1], pos[0]+max[0], pos[1]+max[1], epsx, epsy) ||
689 mouse_on_side(co, pos[0]+max[0], pos[1]+min[1], pos[0]+max[0], pos[1]+max[1], epsx, epsy);
692 static int track_mouse_area(SpaceClip *sc, float co[2], MovieTrackingTrack *track)
694 MovieTrackingMarker *marker= BKE_tracking_get_marker(track, sc->user.framenr);
698 ED_space_clip_size(sc, &width, &height);
700 epsx= MIN4(track->pat_min[0]-track->search_min[0], track->search_max[0]-track->pat_max[0],
701 fabsf(track->pat_min[0]), fabsf(track->pat_max[0])) / 2;
702 epsy= MIN4(track->pat_min[1]-track->search_min[1], track->search_max[1]-track->pat_max[1],
703 fabsf(track->pat_min[1]), fabsf(track->pat_max[1])) / 2;
705 epsx= MAX2(epsy, 2.f / width);
706 epsy= MAX2(epsy, 2.f / height);
708 if(sc->flag&SC_SHOW_MARKER_SEARCH)
709 if(mouse_on_rect(co, marker->pos, track->search_min, track->search_max, epsx, epsy))
710 return TRACK_AREA_SEARCH;
712 if((marker->flag&MARKER_DISABLED)==0) {
713 if(sc->flag&SC_SHOW_MARKER_PATTERN)
714 if(mouse_on_rect(co, marker->pos, track->pat_min, track->pat_max, epsx, epsy))
715 return TRACK_AREA_PAT;
720 if(fabsf(co[0]-marker->pos[0]-track->offset[0])< epsx && fabsf(co[1]-marker->pos[1]-track->offset[1])<=epsy)
721 return TRACK_AREA_POINT;
724 return TRACK_AREA_NONE;
727 static float dist_to_rect(float co[2], float pos[2], float min[2], float max[2])
729 float d1, d2, d3, d4;
730 float p[2]= {co[0]-pos[0], co[1]-pos[1]};
731 float v1[2]= {min[0], min[1]}, v2[2]= {max[0], min[1]},
732 v3[2]= {max[0], max[1]}, v4[2]= {min[0], max[1]};
734 d1= dist_to_line_segment_v2(p, v1, v2);
735 d2= dist_to_line_segment_v2(p, v2, v3);
736 d3= dist_to_line_segment_v2(p, v3, v4);
737 d4= dist_to_line_segment_v2(p, v4, v1);
739 return MIN4(d1, d2, d3, d4);
742 static MovieTrackingTrack *find_nearest_track(SpaceClip *sc, MovieClip *clip, float co[2])
744 MovieTrackingTrack *track= NULL, *cur;
747 cur= clip->tracking.tracks.first;
749 MovieTrackingMarker *marker= BKE_tracking_get_marker(cur, sc->user.framenr);
751 if(((cur->flag&TRACK_HIDDEN)==0) && MARKER_VISIBLE(sc, marker)) {
752 float dist, d1, d2=FLT_MAX, d3=FLT_MAX;
754 d1= sqrtf((co[0]-marker->pos[0]-cur->offset[0])*(co[0]-marker->pos[0]-cur->offset[0])+
755 (co[1]-marker->pos[1]-cur->offset[1])*(co[1]-marker->pos[1]-cur->offset[1])); /* distance to marker point */
757 /* distance to pattern boundbox */
758 if(sc->flag&SC_SHOW_MARKER_PATTERN)
759 d2= dist_to_rect(co, marker->pos, cur->pat_min, cur->pat_max);
761 /* distance to search boundbox */
762 if(sc->flag&SC_SHOW_MARKER_SEARCH)
763 d3= dist_to_rect(co, marker->pos, cur->search_min, cur->search_max);
765 /* choose minimal distance. useful for cases of overlapped markers. */
766 dist= MIN3(d1, d2, d3);
768 if(track==NULL || dist<mindist) {
780 static int mouse_select(bContext *C, float co[2], int extend)
782 SpaceClip *sc= CTX_wm_space_clip(C);
783 MovieClip *clip= ED_space_clip(sc);
784 MovieTrackingTrack *track= NULL; /* selected marker */
787 track= find_nearest_track(sc, clip, co);
789 if((sc->flag&SC_SHOW_MARKER_PATTERN)==0) hidden|= TRACK_AREA_PAT;
790 if((sc->flag&SC_SHOW_MARKER_SEARCH)==0) hidden|= TRACK_AREA_SEARCH;
793 int area= track_mouse_area(sc, co, track);
795 if(!extend || !TRACK_SELECTED(track))
796 area= TRACK_AREA_ALL & ~hidden;
798 if(extend && TRACK_AREA_SELECTED(track, area)) {
799 BKE_movieclip_deselect_track(clip, track, area);
801 if(area==TRACK_AREA_POINT)
802 area= TRACK_AREA_ALL & ~hidden;
804 BKE_movieclip_select_track(clip, track, area, extend);
805 BKE_movieclip_set_selection(clip, MCLIP_SEL_TRACK, track);
809 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, NULL);
811 return OPERATOR_FINISHED;
814 static int select_exec(bContext *C, wmOperator *op)
819 RNA_float_get_array(op->ptr, "location", co);
820 extend= RNA_boolean_get(op->ptr, "extend");
822 return mouse_select(C, co, extend);
825 static int select_invoke(bContext *C, wmOperator *op, wmEvent *event)
829 int extend= RNA_boolean_get(op->ptr, "extend");
832 customdata= slide_marker_customdata(C, event);
834 MEM_freeN(customdata);
835 return OPERATOR_PASS_THROUGH;
839 mouse_pos(C, event, co);
840 RNA_float_set_array(op->ptr, "location", co);
842 return select_exec(C, op);
845 void CLIP_OT_select(wmOperatorType *ot)
849 ot->description= "Select tracking markers";
850 ot->idname= "CLIP_OT_select";
853 ot->exec= select_exec;
854 ot->invoke= select_invoke;
855 ot->poll= space_clip_tracking_poll;
858 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
861 RNA_def_boolean(ot->srna, "extend", 0,
862 "Extend", "Extend selection rather than clearing the existing selection.");
863 RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
864 "Location", "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds.", -100.0f, 100.0f);
867 /********************** border select operator *********************/
869 static int border_select_exec(bContext *C, wmOperator *op)
871 SpaceClip *sc= CTX_wm_space_clip(C);
872 MovieClip *clip= ED_space_clip(sc);
873 MovieTrackingTrack *track;
878 /* get rectangle from operator */
879 rect.xmin= RNA_int_get(op->ptr, "xmin");
880 rect.ymin= RNA_int_get(op->ptr, "ymin");
881 rect.xmax= RNA_int_get(op->ptr, "xmax");
882 rect.ymax= RNA_int_get(op->ptr, "ymax");
884 point_stable_pos(C, rect.xmin, rect.ymin, &rectf.xmin, &rectf.ymin);
885 point_stable_pos(C, rect.xmax, rect.ymax, &rectf.xmax, &rectf.ymax);
887 mode= RNA_int_get(op->ptr, "gesture_mode");
889 /* do actual selection */
890 track= clip->tracking.tracks.first;
892 if((track->flag&TRACK_HIDDEN)==0) {
893 MovieTrackingMarker *marker= BKE_tracking_get_marker(track, sc->user.framenr);
895 if(MARKER_VISIBLE(sc, marker) && BLI_in_rctf(&rectf, marker->pos[0], marker->pos[1])) {
896 BKE_tracking_track_flag(track, TRACK_AREA_ALL, SELECT, mode!=GESTURE_MODAL_SELECT);
905 BKE_movieclip_set_selection(clip, MCLIP_SEL_NONE, NULL);
908 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, NULL);
910 return OPERATOR_FINISHED;
913 return OPERATOR_CANCELLED;
916 void CLIP_OT_select_border(wmOperatorType *ot)
919 ot->name= "Border Select";
920 ot->description= "Select markers using border selection";
921 ot->idname= "CLIP_OT_select_border";
924 ot->invoke= WM_border_select_invoke;
925 ot->exec= border_select_exec;
926 ot->modal= WM_border_select_modal;
927 ot->poll= space_clip_tracking_poll;
930 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
933 WM_operator_properties_gesture_border(ot, FALSE);
936 /********************** circle select operator *********************/
938 static int marker_inside_ellipse(MovieTrackingMarker *marker, float offset[2], float ellipse[2])
940 /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */
943 x= (marker->pos[0] - offset[0])*ellipse[0];
944 y= (marker->pos[1] - offset[1])*ellipse[1];
946 return x*x + y*y < 1.0f;
949 static int circle_select_exec(bContext *C, wmOperator *op)
951 SpaceClip *sc= CTX_wm_space_clip(C);
952 MovieClip *clip= ED_space_clip(sc);
953 ARegion *ar= CTX_wm_region(C);
954 MovieTrackingTrack *track;
955 int x, y, radius, width, height, mode, change= 0;
956 float zoomx, zoomy, offset[2], ellipse[2];
958 /* get operator properties */
959 x= RNA_int_get(op->ptr, "x");
960 y= RNA_int_get(op->ptr, "y");
961 radius= RNA_int_get(op->ptr, "radius");
963 mode= RNA_int_get(op->ptr, "gesture_mode");
965 /* compute ellipse and position in unified coordinates */
966 ED_space_clip_size(sc, &width, &height);
967 ED_space_clip_zoom(sc, ar, &zoomx, &zoomy);
969 ellipse[0]= width*zoomx/radius;
970 ellipse[1]= height*zoomy/radius;
972 point_stable_pos(C, x, y, &offset[0], &offset[1]);
975 track= clip->tracking.tracks.first;
977 if((track->flag&TRACK_HIDDEN)==0) {
978 MovieTrackingMarker *marker= BKE_tracking_get_marker(track, sc->user.framenr);
980 if(MARKER_VISIBLE(sc, marker) && marker_inside_ellipse(marker, offset, ellipse)) {
981 BKE_tracking_track_flag(track, TRACK_AREA_ALL, SELECT, mode!=GESTURE_MODAL_SELECT);
990 BKE_movieclip_set_selection(clip, MCLIP_SEL_NONE, NULL);
993 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, NULL);
995 return OPERATOR_FINISHED;
998 return OPERATOR_CANCELLED;
1001 void CLIP_OT_select_circle(wmOperatorType *ot)
1004 ot->name= "Circle Select";
1005 ot->description= "Select markers using circle selection";
1006 ot->idname= "CLIP_OT_select_circle";
1009 ot->invoke= WM_gesture_circle_invoke;
1010 ot->modal= WM_gesture_circle_modal;
1011 ot->exec= circle_select_exec;
1012 ot->poll= space_clip_tracking_poll;
1015 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1018 RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
1019 RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
1020 RNA_def_int(ot->srna, "radius", 0, INT_MIN, INT_MAX, "Radius", "", INT_MIN, INT_MAX);
1021 RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Gesture Mode", "", INT_MIN, INT_MAX);
1024 /********************** select all operator *********************/
1026 static int select_all_exec(bContext *C, wmOperator *op)
1028 SpaceClip *sc= CTX_wm_space_clip(C);
1029 MovieClip *clip= ED_space_clip(sc);
1030 MovieTrackingTrack *track= NULL; /* selected track */
1031 int action= RNA_enum_get(op->ptr, "action");
1032 int sel_type, framenr= sc->user.framenr;
1035 if(action == SEL_TOGGLE){
1037 track= clip->tracking.tracks.first;
1041 selected|= track->flag&SELECT;
1042 if(sc->flag&SC_SHOW_MARKER_PATTERN) selected|= track->pat_flag&SELECT;
1043 if(sc->flag&SC_SHOW_MARKER_SEARCH) selected|= track->search_flag&SELECT;
1046 action= SEL_DESELECT;
1054 track= clip->tracking.tracks.first;
1056 if((track->flag&TRACK_HIDDEN)==0) {
1057 MovieTrackingMarker *marker= BKE_tracking_get_marker(track, framenr);
1059 if(marker && MARKER_VISIBLE(sc, marker)) {
1062 track->flag|= SELECT;
1063 if(sc->flag&SC_SHOW_MARKER_PATTERN) track->pat_flag|= SELECT;
1064 if(sc->flag&SC_SHOW_MARKER_SEARCH) track->search_flag|= SELECT;
1067 track->flag&= ~SELECT;
1068 track->pat_flag&= ~SELECT;
1069 track->search_flag&= ~SELECT;
1072 track->flag^= SELECT;
1073 if(sc->flag&SC_SHOW_MARKER_PATTERN) track->pat_flag^= SELECT;
1074 if(sc->flag&SC_SHOW_MARKER_SEARCH) track->search_flag^= SELECT;
1083 BKE_movieclip_last_selection(clip, &sel_type, &sel);
1084 if(sel_type==MCLIP_SEL_TRACK)
1085 if(!TRACK_SELECTED(((MovieTrackingTrack*)sel)))
1086 BKE_movieclip_set_selection(clip, MCLIP_SEL_NONE, NULL);
1088 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, NULL);
1090 return OPERATOR_FINISHED;
1093 void CLIP_OT_select_all(wmOperatorType *ot)
1096 ot->name= "Select or Deselect All";
1097 ot->description= "Change selection of all tracking markers";
1098 ot->idname= "CLIP_OT_select_all";
1101 ot->exec= select_all_exec;
1102 ot->poll= space_clip_tracking_poll;
1105 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1107 WM_operator_properties_select_all(ot);
1110 /********************** select grouped operator *********************/
1112 static int select_groped_exec(bContext *C, wmOperator *op)
1114 SpaceClip *sc= CTX_wm_space_clip(C);
1115 MovieClip *clip= ED_space_clip(sc);
1116 MovieTrackingTrack *track, *sel;
1117 MovieTrackingMarker *marker;
1118 int group= RNA_enum_get(op->ptr, "group");
1121 BKE_movieclip_last_selection(clip, &sel_type, (void**)&sel);
1123 track= clip->tracking.tracks.first;
1127 marker= BKE_tracking_get_marker(track, sc->user.framenr);
1129 if(group==0) { /* Keyframed */
1130 ok= marker->framenr==sc->user.framenr && (marker->flag&MARKER_TRACKED)==0;
1132 else if(group==1) { /* Estimated */
1133 ok= marker->framenr!=sc->user.framenr;
1135 else if(group==2) { /* tracked */
1136 ok= marker->framenr==sc->user.framenr && (marker->flag&MARKER_TRACKED);
1138 else if(group==3) { /* locked */
1139 ok= track->flag&TRACK_LOCKED;
1141 else if(group==4) { /* disabled */
1142 ok= marker->flag&MARKER_DISABLED;
1144 else if(group==5) { /* color */
1145 if(sel_type==MCLIP_SEL_TRACK) {
1146 ok= (track->flag&TRACK_CUSTOMCOLOR) == (sel->flag&TRACK_CUSTOMCOLOR);
1148 if(ok && track->flag&TRACK_CUSTOMCOLOR)
1149 ok= equals_v3v3(track->color, sel->color);
1154 track->flag|= SELECT;
1155 if(sc->flag&SC_SHOW_MARKER_PATTERN) track->pat_flag|= SELECT;;
1156 if(sc->flag&SC_SHOW_MARKER_SEARCH) track->search_flag|= SELECT;;
1162 WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, clip);
1164 return OPERATOR_FINISHED;
1167 void CLIP_OT_select_grouped(wmOperatorType *ot)
1169 static EnumPropertyItem select_group_items[] = {
1170 {0, "KEYFRAMED", 0, "Keyframed tracks", "Select all keyframed tracks"},
1171 {1, "ESTIMATED", 0, "Estimated tracks", "Select all estimated tracks"},
1172 {2, "TRACKED", 0, "Tracked tracks", "Select all tracked tracks"},
1173 {3, "LOCKED", 0, "Locked tracks", "Select all locked tracks"},
1174 {4, "DISABLED", 0, "Disabled tracks", "Select all disabled tracks"},
1175 {5, "COLOR", 0, "Tracks with same color", "Select all tracks with same color as actiev track"},
1176 {0, NULL, 0, NULL, NULL}
1180 ot->name= "Join Tracks";
1181 ot->description= "Joint Selected Tracks";
1182 ot->idname= "CLIP_OT_select_grouped";
1185 ot->exec= select_groped_exec;
1186 ot->poll= space_clip_frame_poll;
1189 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1192 RNA_def_enum(ot->srna, "group", select_group_items, TRACK_CLEAR_REMAINED, "Action", "Clear action to execute");
1195 /********************** track operator *********************/
1197 typedef struct TrackMarkersJob {
1198 struct MovieTrackingContext *context; /* tracking context */
1199 int sfra, efra, lastfra; /* Start, end and recently tracked frames */
1200 int backwards; /* Backwards tracking flag */
1201 MovieClip *clip; /* Clip which is tracking */
1202 float delay; /* Delay in milliseconds to allow tracking at fixed FPS */
1205 struct Scene *scene;
1206 struct bScreen *screen;
1209 static int track_markers_testbreak(void)
1214 static void track_init_markers(SpaceClip *sc, MovieClip *clip)
1216 MovieTrackingTrack *track;
1217 int framenr= sc->user.framenr;
1219 track= clip->tracking.tracks.first;
1221 if((track->flag&TRACK_HIDDEN)==0 && (track->flag&TRACK_LOCKED)==0)
1222 BKE_tracking_ensure_marker(track, framenr);
1228 static void track_markers_initjob(bContext *C, TrackMarkersJob *tmj, int backwards)
1230 SpaceClip *sc= CTX_wm_space_clip(C);
1231 MovieClip *clip= ED_space_clip(sc);
1232 Scene *scene= CTX_data_scene(C);
1233 MovieTrackingSettings *settings= &clip->tracking.settings;
1235 tmj->sfra= sc->user.framenr;
1237 tmj->backwards= backwards;
1239 if(backwards) tmj->efra= SFRA;
1240 else tmj->efra= EFRA;
1242 /* limit frames to be tracked by user setting */
1243 if(settings->flag&TRACKING_FRAMES_LIMIT) {
1244 if(backwards) tmj->efra= MAX2(tmj->efra, tmj->sfra-settings->frames_limit);
1245 else tmj->efra= MIN2(tmj->efra, tmj->sfra+settings->frames_limit);
1248 if(settings->speed!=TRACKING_SPEED_FASTEST) {
1249 tmj->delay= 1.0f/scene->r.frs_sec*1000.0f;
1251 if(settings->speed==TRACKING_SPEED_HALF) tmj->delay*= 2;
1252 else if(settings->speed==TRACKING_SPEED_QUARTER) tmj->delay*= 4;
1255 track_init_markers(sc, clip);
1257 tmj->context= BKE_tracking_context_new(clip, &sc->user, backwards);
1259 clip->tracking_context= tmj->context;
1261 tmj->lastfra= tmj->sfra;
1263 /* XXX: silly to store this, but this data is needed to update scene and movieclip
1264 frame numbers when tracking is finished. This introduces better feedback for artists.
1265 Maybe there's another way to solve this problem, but can't think better way atm.
1266 Anyway, this way isn't more unstable as animation rendering animation
1267 which uses the same approach (except storing screen). */
1269 tmj->main= CTX_data_main(C);
1270 tmj->screen= CTX_wm_screen(C);
1273 static void track_markers_startjob(void *tmv, short *stop, short *do_update, float *progress)
1275 TrackMarkersJob *tmj= (TrackMarkersJob *)tmv;
1276 int framenr= tmj->sfra;
1277 //double t= PIL_check_seconds_timer();
1279 while(framenr != tmj->efra) {
1281 /* tracking should happen with fixed fps. Calculate time
1282 using current timer value before tracking frame and after.
1284 Small (and maybe unneeded optimization): do not calculate exec_time
1285 for "Fastest" tracking */
1287 double start_time= PIL_check_seconds_timer(), exec_time;
1289 if(!BKE_tracking_next(tmj->context))
1292 exec_time= PIL_check_seconds_timer()-start_time;
1293 if(tmj->delay>exec_time)
1294 PIL_sleep_ms(tmj->delay-exec_time);
1295 } else if(!BKE_tracking_next(tmj->context))
1299 *progress=(float)(framenr-tmj->sfra) / (tmj->efra-tmj->sfra);
1301 if(tmj->backwards) framenr--;
1304 tmj->lastfra= framenr;
1306 if(*stop || track_markers_testbreak())
1310 //printf("Tracking time: %lf\n", PIL_check_seconds_timer()-t);
1313 static void track_markers_updatejob(void *tmv)
1315 TrackMarkersJob *tmj= (TrackMarkersJob *)tmv;
1317 BKE_tracking_sync(tmj->context);
1320 static void track_markers_freejob(void *tmv)
1322 TrackMarkersJob *tmj= (TrackMarkersJob *)tmv;
1324 tmj->clip->tracking_context= NULL;
1325 tmj->scene->r.cfra= tmj->lastfra;
1326 ED_update_for_newframe(tmj->main, tmj->scene, tmj->screen, 0);
1328 BKE_tracking_sync(tmj->context);
1329 BKE_tracking_context_free(tmj->context);
1333 WM_main_add_notifier(NC_SCENE|ND_FRAME, tmj->scene);
1336 static int track_markers_exec(bContext *C, wmOperator *op)
1338 SpaceClip *sc= CTX_wm_space_clip(C);
1339 MovieClip *clip= ED_space_clip(sc);
1340 Scene *scene= CTX_data_scene(C);
1341 struct MovieTrackingContext *context;
1342 int framenr= sc->user.framenr;
1343 int sfra= framenr, efra;
1344 int backwards= RNA_boolean_get(op->ptr, "backwards");
1345 int sequence= RNA_boolean_get(op->ptr, "sequence");
1346 MovieTrackingSettings *settings= &clip->tracking.settings;
1348 if(backwards) efra= SFRA;
1351 /* limit frames to be tracked by user setting */
1352 if(settings->flag&TRACKING_FRAMES_LIMIT) {
1353 if(backwards) efra= MAX2(efra, sfra-settings->frames_limit);
1354 else efra= MIN2(efra, sfra+settings->frames_limit);
1357 track_init_markers(sc, clip);
1359 context= BKE_tracking_context_new(clip, &sc->user, backwards);
1361 while(framenr != efra) {
1362 if(!BKE_tracking_next(context))
1365 if(backwards) framenr--;
1372 BKE_tracking_sync(context);
1373 BKE_tracking_context_free(context);
1375 /* update scene current frame to the lastes tracked frame */
1376 scene->r.cfra= framenr;
1378 WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
1379 WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
1381 return OPERATOR_FINISHED;
1384 static int track_markers_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
1386 TrackMarkersJob *tmj;
1387 ScrArea *sa= CTX_wm_area(C);
1388 SpaceClip *sc= CTX_wm_space_clip(C);
1389 MovieClip *clip= ED_space_clip(sc);
1391 int backwards= RNA_boolean_get(op->ptr, "backwards");
1392 int sequence= RNA_boolean_get(op->ptr, "sequence");
1394 if(clip->tracking_context)
1395 return OPERATOR_CANCELLED;
1398 return track_markers_exec(C, op);
1400 tmj= MEM_callocN(sizeof(TrackMarkersJob), "TrackMarkersJob data");
1401 track_markers_initjob(C, tmj, backwards);
1404 steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), sa, "Track Markers", WM_JOB_EXCL_RENDER|WM_JOB_PRIORITY|WM_JOB_PROGRESS);
1405 WM_jobs_customdata(steve, tmj, track_markers_freejob);
1407 /* if there's delay set in tracking job, tracking should happen
1408 with fixed FPS. To deal with editor refresh we have to syncronize
1409 tracks from job and tracks in clip. Do this in timer callback
1410 to prevent threading conflicts. */
1411 if(tmj->delay>0) WM_jobs_timer(steve, tmj->delay/1000.0f, NC_MOVIECLIP|NA_EVALUATED, 0);
1412 else WM_jobs_timer(steve, 0.2, NC_MOVIECLIP|NA_EVALUATED, 0);
1414 WM_jobs_callbacks(steve, track_markers_startjob, NULL, track_markers_updatejob, NULL);
1418 WM_jobs_start(CTX_wm_manager(C), steve);
1421 /* add modal handler for ESC */
1422 WM_event_add_modal_handler(C, op);
1424 return OPERATOR_RUNNING_MODAL;
1427 static int track_markers_modal(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
1429 /* no running blender, remove handler and pass through */
1430 if(0==WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C)))
1431 return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
1433 /* running tracking */
1434 switch (event->type) {
1436 return OPERATOR_RUNNING_MODAL;
1440 return OPERATOR_PASS_THROUGH;
1443 void CLIP_OT_track_markers(wmOperatorType *ot)
1446 ot->name= "Track Markers";
1447 ot->description= "Track selected markers";
1448 ot->idname= "CLIP_OT_track_markers";
1451 ot->exec= track_markers_exec;
1452 ot->invoke= track_markers_invoke;
1453 ot->poll= space_clip_frame_poll;
1454 ot->modal= track_markers_modal;
1457 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1460 RNA_def_boolean(ot->srna, "backwards", 0, "Backwards", "Do backwards tarcking");
1461 RNA_def_boolean(ot->srna, "sequence", 0, "Track Sequence", "Track marker during image sequence rather than single image");
1464 /********************** solve camera operator *********************/
1466 static int check_solve_tarck_count(MovieTracking *tracking)
1469 int frame1= tracking->settings.keyframe1, frame2= tracking->settings.keyframe2;
1470 MovieTrackingTrack *track;
1472 track= tracking->tracks.first;
1474 if(BKE_tracking_has_marker(track, frame1))
1475 if(BKE_tracking_has_marker(track, frame2))
1484 static int solve_camera_exec(bContext *C, wmOperator *op)
1486 SpaceClip *sc= CTX_wm_space_clip(C);
1487 MovieClip *clip= ED_space_clip(sc);
1488 Scene *scene= CTX_data_scene(C);
1491 if(!check_solve_tarck_count(&clip->tracking)) {
1492 BKE_report(op->reports, RPT_ERROR, "At least 10 tracks on both of keyframes are needed for reconstruction");
1493 return OPERATOR_CANCELLED;
1496 error = BKE_tracking_solve_reconstruction(clip);
1499 BKE_report(op->reports, RPT_WARNING, "Some data failed to reconstruct, see console for details");
1501 BKE_reportf(op->reports, RPT_INFO, "Average reprojection error %.3f", error);
1506 scene->camera= scene_find_camera(scene);
1509 MovieTracking *tracking= &clip->tracking;
1510 float focal= tracking->camera.focal;
1512 /* set blender camera focal length so result would look fine there */
1514 Camera *camera= (Camera*)scene->camera->data;
1516 if(clip->lastsize[0]) {
1517 camera->sensor_x= tracking->camera.sensor_width;
1518 camera->sensor_y= tracking->camera.sensor_height;
1520 camera->lens= focal*camera->sensor_x/(float)clip->lastsize[0];
1523 WM_event_add_notifier(C, NC_OBJECT, camera);
1527 DAG_id_tag_update(&clip->id, 0);
1529 WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
1530 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, NULL);
1532 return OPERATOR_FINISHED;
1535 void CLIP_OT_solve_camera(wmOperatorType *ot)
1538 ot->name= "Solve Camera";
1539 ot->description= "Solve camera motion from tracks";
1540 ot->idname= "CLIP_OT_solve_camera";
1543 ot->exec= solve_camera_exec;
1544 ot->poll= space_clip_tracking_poll;
1547 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1550 /********************** clear reconstruction operator *********************/
1552 static int clear_reconstruction_exec(bContext *C, wmOperator *UNUSED(op))
1554 SpaceClip *sc= CTX_wm_space_clip(C);
1555 MovieClip *clip= ED_space_clip(sc);
1556 MovieTracking *tracking= &clip->tracking;
1557 MovieTrackingTrack *track= tracking->tracks.first;
1560 track->flag&= ~TRACK_HAS_BUNDLE;
1565 if(tracking->camera.reconstructed)
1566 MEM_freeN(tracking->camera.reconstructed);
1568 tracking->camera.reconstructed= NULL;
1569 tracking->camera.reconnr= 0;
1571 DAG_id_tag_update(&clip->id, 0);
1573 WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
1574 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, NULL);
1576 return OPERATOR_FINISHED;
1579 void CLIP_OT_clear_reconstruction(wmOperatorType *ot)
1582 ot->name= "Clear Reconstruciton";
1583 ot->description= "Clear all reconstruciton data";
1584 ot->idname= "CLIP_OT_clear_reconstruction";
1587 ot->exec= clear_reconstruction_exec;
1588 ot->poll= space_clip_tracking_poll;
1591 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1594 /********************** clear track operator *********************/
1596 static int clear_track_path_exec(bContext *C, wmOperator *op)
1598 SpaceClip *sc= CTX_wm_space_clip(C);
1599 MovieClip *clip= ED_space_clip(sc);
1600 MovieTrackingTrack *track;
1601 int action= RNA_enum_get(op->ptr, "action");
1603 track= clip->tracking.tracks.first;
1605 if(TRACK_SELECTED(track))
1606 BKE_tracking_clear_path(track, sc->user.framenr, action);
1611 WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
1613 return OPERATOR_FINISHED;
1616 void CLIP_OT_clear_track_path(wmOperatorType *ot)
1618 static EnumPropertyItem clear_path_actions[] = {
1619 {TRACK_CLEAR_UPTO, "UPTO", 0, "Clear up-to", "Clear path up to current frame"},
1620 {TRACK_CLEAR_REMAINED, "REMAINED", 0, "Clear remained", "Clear path at remained frames (after current)"},
1621 {TRACK_CLEAR_ALL, "ALL", 0, "Clear all", "Clear the whole path"},
1622 {0, NULL, 0, NULL, NULL}
1626 ot->name= "Clear Track Path";
1627 ot->description= "Clear path of selected tracks";
1628 ot->idname= "CLIP_OT_clear_track_path";
1631 ot->exec= clear_track_path_exec;
1632 ot->poll= space_clip_tracking_poll;
1635 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1638 RNA_def_enum(ot->srna, "action", clear_path_actions, TRACK_CLEAR_REMAINED, "Action", "Clear action to execute");
1641 /********************** disable markers operator *********************/
1643 static int disable_markers_exec(bContext *C, wmOperator *op)
1645 SpaceClip *sc= CTX_wm_space_clip(C);
1646 MovieClip *clip= ED_space_clip(sc);
1647 MovieTracking *tracking= &clip->tracking;
1648 MovieTrackingTrack *track= tracking->tracks.first;
1649 int action= RNA_enum_get(op->ptr, "action");
1652 if(TRACK_SELECTED(track) && (track->flag&TRACK_LOCKED)==0) {
1653 MovieTrackingMarker *marker= BKE_tracking_ensure_marker(track, sc->user.framenr);
1655 if(action==0) marker->flag|= MARKER_DISABLED;
1656 else if(action==1) marker->flag&= ~MARKER_DISABLED;
1657 else marker->flag^= MARKER_DISABLED;
1663 DAG_id_tag_update(&clip->id, 0);
1665 WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
1667 return OPERATOR_FINISHED;
1670 void CLIP_OT_disable_markers(wmOperatorType *ot)
1672 static EnumPropertyItem actions_items[] = {
1673 {0, "DISABLE", 0, "Disable", "Disable selected markers"},
1674 {1, "ENABLE", 0, "Enable", "Enable selected markers"},
1675 {2, "TOGGLE", 0, "Toggle", "Toggle disabled flag for selected markers"},
1676 {0, NULL, 0, NULL, NULL}
1680 ot->name= "Disable Markers";
1681 ot->description= "Disable/enable selected markers";
1682 ot->idname= "CLIP_OT_disable_markers";
1685 ot->exec= disable_markers_exec;
1686 ot->poll= space_clip_tracking_poll;
1689 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1692 RNA_def_enum(ot->srna, "action", actions_items, 0, "Action", "Disable action to execute");
1695 /********************** set origin operator *********************/
1697 static int count_selected_bundles(bContext *C)
1699 SpaceClip *sc= CTX_wm_space_clip(C);
1700 MovieClip *clip= ED_space_clip(sc);
1701 MovieTrackingTrack *track;
1704 track= clip->tracking.tracks.first;
1706 if(TRACK_SELECTED(track))
1715 static int set_origin_exec(bContext *C, wmOperator *op)
1717 SpaceClip *sc= CTX_wm_space_clip(C);
1718 MovieClip *clip= ED_space_clip(sc);
1719 MovieTrackingTrack *track;
1720 Scene *scene= CTX_data_scene(C);
1721 Object *parent= scene->camera;
1722 float mat[4][4], vec[3];
1724 if(count_selected_bundles(C)!=1) {
1725 BKE_report(op->reports, RPT_ERROR, "Track with bundle should be selected to define origin position");
1726 return OPERATOR_CANCELLED;
1729 if(scene->camera->parent)
1730 parent= scene->camera->parent;
1732 track= clip->tracking.tracks.first;
1734 if(TRACK_SELECTED(track))
1740 BKE_get_tracking_mat(scene, mat);
1741 mul_v3_m4v3(vec, mat, track->bundle_pos);
1743 sub_v3_v3(parent->loc, vec);
1745 DAG_id_tag_update(&clip->id, 0);
1746 DAG_id_tag_update(&parent->id, OB_RECALC_OB);
1748 WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
1749 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, NULL);
1751 return OPERATOR_FINISHED;
1754 void CLIP_OT_set_origin(wmOperatorType *ot)
1757 ot->name= "Set Origin";
1758 ot->description= "Set active marker as origin";
1759 ot->idname= "CLIP_OT_set_origin";
1762 ot->exec= set_origin_exec;
1763 ot->poll= space_clip_frame_camera_poll;
1766 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1769 /********************** set floor operator *********************/
1771 static void set_axis(Scene *scene, Object *ob, MovieTrackingTrack *track, char axis)
1773 float mat[4][4], vec[3], obmat[4][4];
1775 BKE_get_tracking_mat(scene, mat);
1776 mul_v3_m4v3(vec, mat, track->bundle_pos);
1778 if(len_v2(vec)<1e-3)
1784 if(fabsf(vec[1])<1e-3) {
1785 mat[0][0]= -1.f; mat[0][1]= 0.f; mat[0][2]= 0.f;
1786 mat[1][0]= 0.f; mat[1][1]= -1.f; mat[1][2]= 0.f;
1787 mat[2][0]= 0.f; mat[2][1]= 0.f; mat[2][2]= 1.0f;
1789 copy_v3_v3(mat[0], vec);
1791 mat[2][0]= 0.f; mat[2][1]= 0.f; mat[2][2]= 1.0f;
1792 cross_v3_v3v3(mat[1], mat[2], mat[0]);
1795 if(fabsf(vec[0])<1e-3) {
1796 mat[0][0]= -1.f; mat[0][1]= 0.f; mat[0][2]= 0.f;
1797 mat[1][0]= 0.f; mat[1][1]= -1.f; mat[1][2]= 0.f;
1798 mat[2][0]= 0.f; mat[2][1]= 0.f; mat[2][2]= 1.0f;
1800 copy_v3_v3(mat[1], vec);
1802 mat[2][0]= 0.f; mat[2][1]= 0.f; mat[2][2]= 1.0f;
1803 cross_v3_v3v3(mat[0], mat[1], mat[2]);
1807 normalize_v3(mat[0]);
1808 normalize_v3(mat[1]);
1809 normalize_v3(mat[2]);
1813 object_to_mat4(ob, obmat);
1814 mul_m4_m4m4(mat, obmat, mat);
1815 object_apply_mat4(ob, mat, 0, 0);
1818 static int set_floor_exec(bContext *C, wmOperator *op)
1820 SpaceClip *sc= CTX_wm_space_clip(C);
1821 MovieClip *clip= ED_space_clip(sc);
1822 Scene *scene= CTX_data_scene(C);
1823 MovieTrackingTrack *track, *sel, *axis_track= NULL;
1824 Object *camera= scene->camera;
1825 Object *parent= camera;
1826 int tot= 0, sel_type;
1827 float vec[3][3], mat[4][4], obmat[4][4], newmat[4][4], orig[3]= {0.f, 0.f, 0.f};
1828 float rot[4][4]={{0.f, 0.f, -1.f, 0.f},
1829 {0.f, 1.f, 0.f, 0.f},
1830 {1.f, 0.f, 0.f, 0.f},
1831 {0.f, 0.f, 0.f, 1.f}}; /* 90 degrees Y-axis rotation matrix */
1833 if(count_selected_bundles(C)!=3) {
1834 BKE_report(op->reports, RPT_ERROR, "Three tracks with bundles are needed to orient the floor");
1835 return OPERATOR_CANCELLED;
1838 if(scene->camera->parent)
1839 parent= scene->camera->parent;
1841 BKE_get_tracking_mat(scene, mat);
1843 BKE_movieclip_last_selection(clip, &sel_type, (void**)&sel);
1845 /* get 3 bundles to use as reference */
1846 track= clip->tracking.tracks.first;
1847 while(track && tot<3) {
1848 if(track->flag&TRACK_HAS_BUNDLE && TRACK_SELECTED(track)) {
1849 mul_v3_m4v3(vec[tot], mat, track->bundle_pos);
1851 if(tot==0 || (sel_type==MCLIP_SEL_TRACK && track==sel))
1852 copy_v3_v3(orig, vec[tot]);
1862 sub_v3_v3(vec[1], vec[0]);
1863 sub_v3_v3(vec[2], vec[0]);
1865 /* construct ortho-normal basis */
1868 cross_v3_v3v3(mat[0], vec[1], vec[2]);
1869 copy_v3_v3(mat[1], vec[1]);
1870 cross_v3_v3v3(mat[2], mat[0], mat[1]);
1872 normalize_v3(mat[0]);
1873 normalize_v3(mat[1]);
1874 normalize_v3(mat[2]);
1876 /* move to origin point */
1883 object_to_mat4(parent, obmat);
1884 mul_m4_m4m4(mat, obmat, mat);
1885 mul_m4_m4m4(newmat, mat, rot);
1886 object_apply_mat4(parent, newmat, 0, 0);
1888 /* make camera have positive z-coordinate */
1889 mul_v3_m4v3(vec[0], mat, camera->loc);
1890 if(camera->loc[2]<0) {
1892 mul_m4_m4m4(newmat, mat, rot);
1893 object_apply_mat4(camera, newmat, 0, 0);
1896 where_is_object(scene, parent);
1897 set_axis(scene, parent, axis_track, 'X');
1899 DAG_id_tag_update(&clip->id, 0);
1900 DAG_id_tag_update(&parent->id, OB_RECALC_OB);
1902 WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
1903 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, NULL);
1905 return OPERATOR_FINISHED;
1908 void CLIP_OT_set_floor(wmOperatorType *ot)
1911 ot->name= "Set Floor";
1912 ot->description= "Set floor using 3 selected bundles";
1913 ot->idname= "CLIP_OT_set_floor";
1916 ot->exec= set_floor_exec;
1917 ot->poll= space_clip_camera_poll;
1920 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1923 /********************** set origin operator *********************/
1925 static int set_axis_exec(bContext *C, wmOperator *op)
1927 SpaceClip *sc= CTX_wm_space_clip(C);
1928 MovieClip *clip= ED_space_clip(sc);
1929 MovieTrackingTrack *track;
1930 Scene *scene= CTX_data_scene(C);
1931 Object *parent= scene->camera;
1932 int axis= RNA_enum_get(op->ptr, "axis");
1934 if(count_selected_bundles(C)!=1) {
1935 BKE_report(op->reports, RPT_ERROR, "Track with bundle should be selected to define X-axis");
1937 return OPERATOR_CANCELLED;
1940 if(scene->camera->parent)
1941 parent= scene->camera->parent;
1943 track= clip->tracking.tracks.first;
1945 if(TRACK_SELECTED(track))
1951 set_axis(scene, parent, track, axis==0?'X':'Y');
1953 DAG_id_tag_update(&clip->id, 0);
1954 DAG_id_tag_update(&parent->id, OB_RECALC_OB);
1956 WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
1957 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, NULL);
1959 return OPERATOR_FINISHED;
1962 void CLIP_OT_set_axis(wmOperatorType *ot)
1964 static EnumPropertyItem axis_actions[] = {
1965 {0, "X", 0, "X", "Align bundle align X axis"},
1966 {1, "Y", 0, "Y", "Align bundle align Y axis"},
1967 {0, NULL, 0, NULL, NULL}
1971 ot->name= "Set Axis";
1972 ot->description= "Set direction of scene axis";
1973 ot->idname= "CLIP_OT_set_axis";
1976 ot->exec= set_axis_exec;
1977 ot->poll= space_clip_frame_camera_poll;
1980 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1983 RNA_def_enum(ot->srna, "axis", axis_actions, 0, "Axis", "Axis to use to align bundle along");
1986 /********************** set scale operator *********************/
1988 static int set_scale_exec(bContext *C, wmOperator *op)
1990 SpaceClip *sc= CTX_wm_space_clip(C);
1991 MovieClip *clip= ED_space_clip(sc);
1992 MovieTrackingTrack *track;
1993 Scene *scene= CTX_data_scene(C);
1994 Object *parent= scene->camera;
1996 float vec[2][3], mat[4][4], scale;
1998 if(count_selected_bundles(C)!=2) {
1999 BKE_report(op->reports, RPT_ERROR, "Two tracks with bundles should be selected to scale scene");
2001 return OPERATOR_CANCELLED;
2004 if(scene->camera->parent)
2005 parent= scene->camera->parent;
2007 BKE_get_tracking_mat(scene, mat);
2009 track= clip->tracking.tracks.first;
2011 if(TRACK_SELECTED(track)) {
2012 mul_v3_m4v3(vec[tot], mat, track->bundle_pos);
2019 sub_v3_v3(vec[0], vec[1]);
2021 if(len_v3(vec[0])>1e-5) {
2022 scale= clip->tracking.settings.dist / len_v3(vec[0]);
2024 mul_v3_fl(parent->size, scale);
2025 mul_v3_fl(parent->loc, scale);
2027 DAG_id_tag_update(&clip->id, 0);
2028 DAG_id_tag_update(&parent->id, OB_RECALC_OB);
2030 WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
2031 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, NULL);
2034 return OPERATOR_FINISHED;
2037 void CLIP_OT_set_scale(wmOperatorType *ot)
2040 ot->name= "Set Scale";
2041 ot->description= "Set scale of scene";
2042 ot->idname= "CLIP_OT_set_scale";
2045 ot->exec= set_scale_exec;
2046 ot->poll= space_clip_frame_camera_poll;
2049 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2052 /********************** set principal center operator *********************/
2054 static int set_center_principal_exec(bContext *C, wmOperator *UNUSED(op))
2056 SpaceClip *sc= CTX_wm_space_clip(C);
2057 MovieClip *clip= ED_space_clip(sc);
2060 BKE_movieclip_acquire_size(clip, &sc->user, &width, &height);
2062 if(width==0 || height==0)
2063 return OPERATOR_CANCELLED;
2065 clip->tracking.camera.principal[0]= ((float)width)/2.0f;
2066 clip->tracking.camera.principal[1]= ((float)height)/2.0f;
2068 WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, clip);
2070 return OPERATOR_FINISHED;
2073 void CLIP_OT_set_center_principal(wmOperatorType *ot)
2076 ot->name= "Set Principal to Center";
2077 ot->description= "Set principal point to center of footage";
2078 ot->idname= "CLIP_OT_set_center_principal";
2081 ot->exec= set_center_principal_exec;
2082 ot->poll= space_clip_tracking_poll;
2085 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2088 /********************** hide tracks operator *********************/
2090 static int hide_tracks_exec(bContext *C, wmOperator *op)
2092 SpaceClip *sc= CTX_wm_space_clip(C);
2093 MovieClip *clip= ED_space_clip(sc);
2094 MovieTrackingTrack *track;
2095 int sel_type, unselected;
2098 unselected= RNA_boolean_get(op->ptr, "unselected");
2100 BKE_movieclip_last_selection(clip, &sel_type, &sel);
2102 track= clip->tracking.tracks.first;
2104 if(unselected==0 && TRACK_SELECTED(track)) {
2105 track->flag|= TRACK_HIDDEN;
2106 } else if(unselected==1 && !TRACK_SELECTED(track)) {
2107 track->flag|= TRACK_HIDDEN;
2113 if(sel_type==MCLIP_SEL_TRACK) {
2114 track= (MovieTrackingTrack *)sel;
2116 if(track->flag&TRACK_HIDDEN)
2117 BKE_movieclip_set_selection(clip, MCLIP_SEL_NONE, NULL);
2120 WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, NULL);
2122 return OPERATOR_FINISHED;
2125 void CLIP_OT_hide_tracks(wmOperatorType *ot)
2128 ot->name= "Hide Tracks";
2129 ot->description= "Hide selected tracks";
2130 ot->idname= "CLIP_OT_hide_tracks";
2133 ot->exec= hide_tracks_exec;
2134 ot->poll= space_clip_tracking_poll;
2137 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2140 RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected tracks");
2143 /********************** hide tracks clear operator *********************/
2145 static int hide_tracks_clear_exec(bContext *C, wmOperator *UNUSED(op))
2147 SpaceClip *sc= CTX_wm_space_clip(C);
2148 MovieClip *clip= ED_space_clip(sc);
2149 MovieTrackingTrack *track;
2151 track= clip->tracking.tracks.first;
2153 track->flag&= ~TRACK_HIDDEN;
2158 WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, NULL);
2160 return OPERATOR_FINISHED;
2163 void CLIP_OT_hide_tracks_clear(wmOperatorType *ot)
2166 ot->name= "Hide Tracks Clear";
2167 ot->description= "Clear hide selected tracks";
2168 ot->idname= "CLIP_OT_hide_tracks_clear";
2171 ot->exec= hide_tracks_clear_exec;
2172 ot->poll= space_clip_tracking_poll;
2175 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2178 /********************** detect features operator *********************/
2180 static int detect_features_exec(bContext *C, wmOperator *UNUSED(op))
2182 SpaceClip *sc= CTX_wm_space_clip(C);
2183 MovieClip *clip= ED_space_clip(sc);
2184 ImBuf *ibuf= BKE_movieclip_acquire_ibuf(clip, &sc->user);
2185 MovieTrackingTrack *track= clip->tracking.tracks.first;
2187 /* deselect existing tracks */
2189 track->flag&= ~SELECT;
2190 track->pat_flag&= ~SELECT;
2191 track->search_flag&= ~SELECT;
2196 BKE_tracking_detect(&clip->tracking, ibuf, sc->user.framenr);
2198 IMB_freeImBuf(ibuf);
2200 BKE_movieclip_set_selection(clip, MCLIP_SEL_NONE, NULL);
2201 WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, NULL);
2203 return OPERATOR_FINISHED;
2206 void CLIP_OT_detect_features(wmOperatorType *ot)
2209 ot->name= "Detect Features";
2210 ot->description= "Automatically detect features to track";
2211 ot->idname= "CLIP_OT_detect_features";
2214 ot->exec= detect_features_exec;
2215 ot->poll= space_clip_frame_poll;
2218 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2221 /********************** frame jump operator *********************/
2223 static int frame_jump_exec(bContext *C, wmOperator *op)
2225 Scene *scene= CTX_data_scene(C);
2226 SpaceClip *sc= CTX_wm_space_clip(C);
2227 MovieClip *clip= ED_space_clip(sc);
2228 MovieTrackingTrack *track;
2229 int end= RNA_boolean_get(op->ptr, "end");
2230 int sel_type, delta= end ? 1 : -1;
2232 BKE_movieclip_last_selection(clip, &sel_type, (void**)&track);
2234 if(sel_type!=MCLIP_SEL_TRACK)
2235 return OPERATOR_CANCELLED;
2237 while(BKE_tracking_has_marker(track, sc->user.framenr+delta)) {
2238 sc->user.framenr+= delta;
2241 if(CFRA!=sc->user.framenr) {
2242 CFRA= sc->user.framenr;
2243 sound_seek_scene(C);
2245 WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
2248 WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, NULL);
2250 return OPERATOR_FINISHED;
2253 void CLIP_OT_frame_jump(wmOperatorType *ot)
2256 ot->name= "Jump to Frame";
2257 ot->description= "Jump to special frame";
2258 ot->idname= "CLIP_OT_frame_jump";
2261 ot->exec= frame_jump_exec;
2262 ot->poll= space_clip_frame_poll;
2265 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2268 RNA_def_boolean(ot->srna, "end", 0, "Last Frame", "Jump to the last frame of current track.");
2271 /********************** join tracks operator *********************/
2273 static int join_tracks_exec(bContext *C, wmOperator *op)
2275 SpaceClip *sc= CTX_wm_space_clip(C);
2276 MovieClip *clip= ED_space_clip(sc);
2277 MovieTrackingTrack *act_track, *track, *next;
2280 BKE_movieclip_last_selection(clip, &sel_type, (void**)&act_track);
2282 if(sel_type!=MCLIP_SEL_TRACK) {
2283 BKE_report(op->reports, RPT_ERROR, "No active track to join to");
2284 return OPERATOR_CANCELLED;
2287 track= clip->tracking.tracks.first;
2289 if(TRACK_SELECTED(track) && track!=act_track) {
2290 if(!BKE_tracking_test_join_tracks(act_track, track)) {
2291 BKE_report(op->reports, RPT_ERROR, "Some selected tracks have got keyframed markers to the same frame");
2292 return OPERATOR_CANCELLED;
2299 track= clip->tracking.tracks.first;
2303 if(TRACK_SELECTED(track) && track!=act_track) {
2304 BKE_tracking_join_tracks(act_track, track);
2306 BKE_tracking_free_track(track);
2307 BLI_freelinkN(&clip->tracking.tracks, track);
2313 WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, clip);
2315 return OPERATOR_FINISHED;
2318 void CLIP_OT_join_tracks(wmOperatorType *ot)
2321 ot->name= "Join Tracks";
2322 ot->description= "Joint Selected Tracks";
2323 ot->idname= "CLIP_OT_join_tracks";
2326 ot->exec= join_tracks_exec;
2327 ot->poll= space_clip_frame_poll;
2330 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2333 /********************** lock tracks operator *********************/
2335 static int lock_tracks_exec(bContext *C, wmOperator *op)
2337 SpaceClip *sc= CTX_wm_space_clip(C);
2338 MovieClip *clip= ED_space_clip(sc);
2339 MovieTracking *tracking= &clip->tracking;
2340 MovieTrackingTrack *track= tracking->tracks.first;
2341 int action= RNA_enum_get(op->ptr, "action");
2344 if(TRACK_SELECTED(track)) {
2345 if(action==0) track->flag|= TRACK_LOCKED;
2346 else if(action==1) track->flag&= ~TRACK_LOCKED;
2347 else track->flag^= TRACK_LOCKED;
2353 WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
2355 return OPERATOR_FINISHED;
2358 void CLIP_OT_lock_tracks(wmOperatorType *ot)
2360 static EnumPropertyItem actions_items[] = {
2361 {0, "LOCK", 0, "Lock", "Lock selected tracks"},
2362 {1, "UNLOCK", 0, "Unlock", "Unlock selected tracks"},
2363 {2, "TOGGLE", 0, "Toggle", "Toggle locked flag for selected tracks"},
2364 {0, NULL, 0, NULL, NULL}
2368 ot->name= "Lock Tracks";
2369 ot->description= "Lock/unlock selected tracks";
2370 ot->idname= "CLIP_OT_lock_tracks";
2373 ot->exec= lock_tracks_exec;
2374 ot->poll= space_clip_tracking_poll;
2377 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2380 RNA_def_enum(ot->srna, "action", actions_items, 0, "Action", "Lock action to execute");
2383 /********************** track copy color operator *********************/
2385 static int track_copy_color_exec(bContext *C, wmOperator *UNUSED(op))
2387 SpaceClip *sc= CTX_wm_space_clip(C);
2388 MovieClip *clip= ED_space_clip(sc);
2389 MovieTrackingTrack *track, *sel;
2392 BKE_movieclip_last_selection(clip, &sel_type, (void**)&sel);
2394 if(sel_type!=MCLIP_SEL_TRACK)
2395 return OPERATOR_CANCELLED;
2397 track= clip->tracking.tracks.first;
2399 if(TRACK_SELECTED(track) && track!=sel) {
2400 track->flag&= ~TRACK_CUSTOMCOLOR;
2402 if(sel->flag&TRACK_CUSTOMCOLOR) {
2403 copy_v3_v3(track->color, sel->color);
2404 track->flag|= TRACK_CUSTOMCOLOR;
2411 WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, clip);
2413 return OPERATOR_FINISHED;
2416 void CLIP_OT_track_copy_color(wmOperatorType *ot)
2419 ot->name= "Copy Color";
2420 ot->description= "Copy color to all selected tracks";
2421 ot->idname= "CLIP_OT_track_copy_color";
2424 ot->exec= track_copy_color_exec;
2425 ot->poll= space_clip_tracking_poll;
2428 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2431 /********************** add 2d stabilization tracks operator *********************/
2433 static int stabilize_2d_add_exec(bContext *C, wmOperator *UNUSED(op))
2435 SpaceClip *sc= CTX_wm_space_clip(C);
2436 MovieClip *clip= ED_space_clip(sc);
2437 MovieTracking *tracking= &clip->tracking;
2438 MovieTrackingTrack *track;
2439 MovieTrackingStabilization *stab= &tracking->stabilization;
2441 track= tracking->tracks.first;
2443 if(TRACK_SELECTED(track)) {
2444 track->flag|= TRACK_USE_2D_STAB;
2453 DAG_id_tag_update(&clip->id, 0);
2454 WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, clip);
2456 return OPERATOR_FINISHED;
2459 void CLIP_OT_stabilize_2d_add(wmOperatorType *ot)
2462 ot->name= "Add Stabilization Tracks";
2463 ot->description= "Add selected tracks to 2D stabilization tool";
2464 ot->idname= "CLIP_OT_stabilize_2d_add";
2467 ot->exec= stabilize_2d_add_exec;
2468 ot->poll= space_clip_tracking_poll;
2471 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2474 /********************** remove 2d stabilization tracks operator *********************/
2476 static int stabilize_2d_remove_exec(bContext *C, wmOperator *UNUSED(op))
2478 SpaceClip *sc= CTX_wm_space_clip(C);
2479 MovieClip *clip= ED_space_clip(sc);
2480 MovieTracking *tracking= &clip->tracking;
2481 MovieTrackingStabilization *stab= &tracking->stabilization;
2482 MovieTrackingTrack *track;
2485 track= tracking->tracks.first;
2487 if(track->flag&TRACK_USE_2D_STAB) {
2488 if(a==stab->act_track) {
2489 track->flag&= ~TRACK_USE_2D_STAB;
2494 if(stab->act_track<0)
2508 DAG_id_tag_update(&clip->id, 0);
2509 WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, clip);
2511 return OPERATOR_FINISHED;
2514 void CLIP_OT_stabilize_2d_remove(wmOperatorType *ot)
2517 ot->name= "Remove Stabilization Track";
2518 ot->description= "Remove selected track from stabilization";
2519 ot->idname= "CLIP_OT_stabilize_2d_remove";
2522 ot->exec= stabilize_2d_remove_exec;
2523 ot->poll= space_clip_tracking_poll;
2526 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2529 /********************** select 2d stabilization tracks operator *********************/
2531 static int stabilize_2d_select_exec(bContext *C, wmOperator *UNUSED(op))
2533 SpaceClip *sc= CTX_wm_space_clip(C);
2534 MovieClip *clip= ED_space_clip(sc);
2535 MovieTracking *tracking= &clip->tracking;
2536 MovieTrackingTrack *track;
2539 area= TRACK_AREA_POINT;
2540 if(sc->flag&SC_SHOW_MARKER_PATTERN) area|= TRACK_AREA_PAT;
2541 if(sc->flag&SC_SHOW_MARKER_SEARCH) area|= TRACK_AREA_SEARCH;
2543 track= tracking->tracks.first;
2545 if(track->flag&TRACK_USE_2D_STAB) {
2546 BKE_tracking_track_flag(track, area, SELECT, 0);
2554 WM_event_add_notifier(C, NC_MOVIECLIP|ND_SELECT, clip);
2556 return OPERATOR_FINISHED;
2559 void CLIP_OT_stabilize_2d_select(wmOperatorType *ot)
2562 ot->name= "Select Stabilization Tracks";
2563 ot->description= "Select track whic hare used for stabilization";
2564 ot->idname= "CLIP_OT_stabilize_2d_select";
2567 ot->exec= stabilize_2d_select_exec;
2568 ot->poll= space_clip_tracking_poll;
2571 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;