2 * ***** BEGIN GPL LICENSE BLOCK *****
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.
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.
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.
18 * The Original Code is Copyright (C) 2011 Blender Foundation.
19 * All rights reserved.
22 * Contributor(s): Blender Foundation,
25 * ***** END GPL LICENSE BLOCK *****
28 /** \file blender/editors/space_clip/tracking_ops.c
32 #include "MEM_guardedalloc.h"
34 #include "DNA_camera_types.h"
35 #include "DNA_constraint_types.h"
36 #include "DNA_gpencil_types.h"
37 #include "DNA_mask_types.h"
38 #include "DNA_movieclip_types.h"
39 #include "DNA_object_types.h" /* SELECT */
40 #include "DNA_scene_types.h"
42 #include "BLI_utildefines.h"
44 #include "BLI_listbase.h"
46 #include "BLI_blenlib.h"
49 #include "BKE_context.h"
50 #include "BKE_constraint.h"
51 #include "BKE_movieclip.h"
52 #include "BKE_tracking.h"
53 #include "BKE_global.h"
54 #include "BKE_depsgraph.h"
55 #include "BKE_object.h"
56 #include "BKE_report.h"
57 #include "BKE_scene.h"
58 #include "BKE_library.h"
61 #include "BKE_sound.h"
66 #include "ED_screen.h"
68 #include "ED_keyframing.h"
70 #include "IMB_imbuf_types.h"
71 #include "IMB_imbuf.h"
73 #include "UI_interface.h"
75 #include "RNA_access.h"
76 #include "RNA_define.h"
78 #include "BLF_translation.h"
82 #include "UI_view2d.h"
84 #include "clip_intern.h" // own include
86 /********************** add marker operator *********************/
88 static bool add_marker(const bContext *C, float x, float y)
90 SpaceClip *sc = CTX_wm_space_clip(C);
91 MovieClip *clip = ED_space_clip_get_clip(sc);
92 MovieTracking *tracking = &clip->tracking;
93 ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
94 ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
95 MovieTrackingTrack *track;
97 int framenr = ED_space_clip_get_clip_frame_number(sc);
99 ED_space_clip_get_size(sc, &width, &height);
101 if (width == 0 || height == 0) {
105 track = BKE_tracking_track_add(tracking, tracksbase, x, y, framenr, width, height);
107 BKE_tracking_track_select(tracksbase, track, TRACK_AREA_ALL, 0);
108 BKE_tracking_plane_tracks_deselect_all(plane_tracks_base);
110 clip->tracking.act_track = track;
111 clip->tracking.act_plane_track = NULL;
116 static int add_marker_exec(bContext *C, wmOperator *op)
118 SpaceClip *sc = CTX_wm_space_clip(C);
119 MovieClip *clip = ED_space_clip_get_clip(sc);
122 RNA_float_get_array(op->ptr, "location", pos);
124 if (!add_marker(C, pos[0], pos[1])) {
125 return OPERATOR_CANCELLED;
128 /* reset offset from locked position, so frame jumping wouldn't be so confusing */
132 WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip);
134 return OPERATOR_FINISHED;
137 static int add_marker_invoke(bContext *C, wmOperator *op, const wmEvent *event)
139 SpaceClip *sc = CTX_wm_space_clip(C);
140 ARegion *ar = CTX_wm_region(C);
142 if (!RNA_struct_property_is_set(op->ptr, "location")) {
143 /* If location is not set, use mouse positio nas default. */
145 ED_clip_mouse_pos(sc, ar, event->mval, co);
146 RNA_float_set_array(op->ptr, "location", co);
149 return add_marker_exec(C, op);
152 void CLIP_OT_add_marker(wmOperatorType *ot)
155 ot->name = "Add Marker";
156 ot->idname = "CLIP_OT_add_marker";
157 ot->description = "Place new marker at specified location";
160 ot->invoke = add_marker_invoke;
161 ot->exec = add_marker_exec;
162 ot->poll = ED_space_clip_tracking_poll;
165 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
168 RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
169 "Location", "Location of marker on frame", -1.0f, 1.0f);
172 /********************** add marker operator *********************/
174 static int add_marker_at_click_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
176 ED_area_headerprint(CTX_wm_area(C), IFACE_("Use LMB click to define location where place the marker"));
178 /* add modal handler for ESC */
179 WM_event_add_modal_handler(C, op);
181 return OPERATOR_RUNNING_MODAL;
184 static int add_marker_at_click_modal(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
186 SpaceClip *sc = CTX_wm_space_clip(C);
187 MovieClip *clip = ED_space_clip_get_clip(sc);
188 ARegion *ar = CTX_wm_region(C);
191 switch (event->type) {
193 return OPERATOR_RUNNING_MODAL;
197 ED_area_headerprint(CTX_wm_area(C), NULL);
199 ED_clip_point_stable_pos(sc, ar,
200 event->x - ar->winrct.xmin,
201 event->y - ar->winrct.ymin,
204 if (!add_marker(C, pos[0], pos[1]))
205 return OPERATOR_CANCELLED;
207 WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip);
208 return OPERATOR_FINISHED;
212 ED_area_headerprint(CTX_wm_area(C), NULL);
213 return OPERATOR_CANCELLED;
216 return OPERATOR_PASS_THROUGH;
219 void CLIP_OT_add_marker_at_click(wmOperatorType *ot)
222 ot->name = "Add Marker at Click";
223 ot->idname = "CLIP_OT_add_marker_at_click";
224 ot->description = "Place new marker at the desired (clicked) position";
227 ot->invoke = add_marker_at_click_invoke;
228 ot->poll = ED_space_clip_tracking_poll;
229 ot->modal = add_marker_at_click_modal;
232 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
235 /********************** delete track operator *********************/
237 static int delete_track_exec(bContext *C, wmOperator *UNUSED(op))
239 SpaceClip *sc = CTX_wm_space_clip(C);
240 MovieClip *clip = ED_space_clip_get_clip(sc);
241 MovieTracking *tracking = &clip->tracking;
242 ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
243 ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
244 MovieTrackingTrack *track = tracksbase->first, *next;
245 MovieTrackingPlaneTrack *plane_track, *next_plane_track;
246 bool modified = false;
248 /* Delete selected plane tracks. */
249 for (plane_track = plane_tracks_base->first;
251 plane_track = next_plane_track)
253 next_plane_track = plane_track->next;
255 if (plane_track->flag & SELECT) {
256 BKE_tracking_plane_track_free(plane_track);
257 BLI_freelinkN(plane_tracks_base, plane_track);
262 /* Remove selected point tracks (they'll also be removed from planes which uses them). */
266 if (TRACK_VIEW_SELECTED(sc, track))
267 clip_delete_track(C, clip, track);
272 /* nothing selected now, unlock view so it can be scrolled nice again */
273 sc->flag &= ~SC_LOCK_SELECTION;
276 WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip);
279 return OPERATOR_FINISHED;
282 void CLIP_OT_delete_track(wmOperatorType *ot)
285 ot->name = "Delete Track";
286 ot->idname = "CLIP_OT_delete_track";
287 ot->description = "Delete selected tracks";
290 ot->invoke = WM_operator_confirm;
291 ot->exec = delete_track_exec;
292 ot->poll = ED_space_clip_tracking_poll;
295 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
298 /********************** delete marker operator *********************/
300 static int delete_marker_exec(bContext *C, wmOperator *UNUSED(op))
302 SpaceClip *sc = CTX_wm_space_clip(C);
303 MovieClip *clip = ED_space_clip_get_clip(sc);
304 ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
305 ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking);
306 MovieTrackingTrack *track = tracksbase->first, *next;
307 MovieTrackingPlaneTrack *plane_track, *plane_track_next;
308 int framenr = ED_space_clip_get_clip_frame_number(sc);
309 int has_selection = 0;
314 if (TRACK_VIEW_SELECTED(sc, track)) {
315 MovieTrackingMarker *marker = BKE_tracking_marker_get_exact(track, framenr);
318 has_selection |= track->markersnr > 1;
320 clip_delete_marker(C, clip, track, marker);
327 for (plane_track = plane_tracks_base->first;
329 plane_track = plane_track_next)
331 plane_track_next = plane_track->next;
333 if (plane_track->flag & SELECT) {
334 MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get_exact(plane_track, framenr);
337 if (plane_track->markersnr == 1) {
338 BKE_tracking_plane_track_free(plane_track);
339 BLI_freelinkN(plane_tracks_base, plane_track);
342 BKE_tracking_plane_marker_delete(plane_track, framenr);
348 if (!has_selection) {
349 /* nothing selected now, unlock view so it can be scrolled nice again */
350 sc->flag &= ~SC_LOCK_SELECTION;
353 return OPERATOR_FINISHED;
356 void CLIP_OT_delete_marker(wmOperatorType *ot)
359 ot->name = "Delete Marker";
360 ot->idname = "CLIP_OT_delete_marker";
361 ot->description = "Delete marker for current frame from selected tracks";
364 ot->invoke = WM_operator_confirm;
365 ot->exec = delete_marker_exec;
366 ot->poll = ED_space_clip_tracking_poll;
369 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
372 /********************** slide marker operator *********************/
374 #define SLIDE_ACTION_POS 0
375 #define SLIDE_ACTION_SIZE 1
376 #define SLIDE_ACTION_OFFSET 2
377 #define SLIDE_ACTION_TILT_SIZE 3
381 MovieTrackingTrack *track;
382 MovieTrackingMarker *marker;
386 float *min, *max, *pos, *offset, (*corners)[2];
389 short lock, accurate;
391 /* data to restore on cancel */
392 float old_search_min[2], old_search_max[2], old_pos[2], old_offset[2];
393 float old_corners[4][2];
394 float (*old_markers)[2];
397 static void slide_marker_tilt_slider(MovieTrackingMarker *marker, float slider[2])
399 add_v2_v2v2(slider, marker->pattern_corners[1], marker->pattern_corners[2]);
400 add_v2_v2(slider, marker->pos);
403 static SlideMarkerData *create_slide_marker_data(SpaceClip *sc, MovieTrackingTrack *track,
404 MovieTrackingMarker *marker, const wmEvent *event,
405 int area, int corner, int action, int width, int height)
407 SlideMarkerData *data = MEM_callocN(sizeof(SlideMarkerData), "slide marker data");
408 int framenr = ED_space_clip_get_clip_frame_number(sc);
410 marker = BKE_tracking_marker_ensure(track, framenr);
413 data->action = action;
415 data->marker = marker;
417 if (area == TRACK_AREA_POINT) {
418 data->pos = marker->pos;
419 data->offset = track->offset;
421 else if (area == TRACK_AREA_PAT) {
422 if (action == SLIDE_ACTION_SIZE) {
423 data->corners = marker->pattern_corners;
425 else if (action == SLIDE_ACTION_OFFSET) {
428 data->pos = marker->pos;
429 data->offset = track->offset;
431 data->old_markers = MEM_callocN(sizeof(*data->old_markers) * track->markersnr, "slide marekrs");
432 for (a = 0; a < track->markersnr; a++)
433 copy_v2_v2(data->old_markers[a], track->markers[a].pos);
435 else if (action == SLIDE_ACTION_POS) {
436 data->corners = marker->pattern_corners;
437 data->pos = marker->pattern_corners[corner];
438 copy_v2_v2(data->spos, data->pos);
440 else if (action == SLIDE_ACTION_TILT_SIZE) {
441 data->corners = marker->pattern_corners;
442 slide_marker_tilt_slider(marker, data->spos);
445 else if (area == TRACK_AREA_SEARCH) {
446 data->min = marker->search_min;
447 data->max = marker->search_max;
450 data->mval[0] = event->mval[0];
451 data->mval[1] = event->mval[1];
454 data->height = height;
456 if (action == SLIDE_ACTION_SIZE)
459 /* backup marker's settings */
460 memcpy(data->old_corners, marker->pattern_corners, sizeof(data->old_corners));
461 copy_v2_v2(data->old_search_min, marker->search_min);
462 copy_v2_v2(data->old_search_max, marker->search_max);
463 copy_v2_v2(data->old_pos, marker->pos);
464 copy_v2_v2(data->old_offset, track->offset);
469 static int mouse_on_slide_zone(SpaceClip *sc, MovieTrackingMarker *marker,
470 int area, float co[2], float slide_zone[2],
471 float padding, int width, int height)
473 const float size = 12.0f;
474 float min[2], max[2];
477 if (area == TRACK_AREA_SEARCH) {
478 copy_v2_v2(min, marker->search_min);
479 copy_v2_v2(max, marker->search_max);
482 BKE_tracking_marker_pattern_minmax(marker, min, max);
485 min[0] -= padding / width;
486 min[1] -= padding / height;
487 max[0] += padding / width;
488 max[1] += padding / height;
490 dx = size / width / sc->zoom;
491 dy = size / height / sc->zoom;
493 dx = min_ff(dx, (max[0] - min[0]) / 6.0f);
494 dy = min_ff(dy, (max[1] - min[1]) / 6.0f);
496 return IN_RANGE_INCL(co[0], slide_zone[0] - dx, slide_zone[0] + dx) &&
497 IN_RANGE_INCL(co[1], slide_zone[1] - dy, slide_zone[1] + dy);
500 static int mouse_on_corner(SpaceClip *sc, MovieTrackingMarker *marker,
501 int area, float co[2], int corner, float padding,
502 int width, int height)
504 float min[2], max[2], crn[2];
506 if (area == TRACK_AREA_SEARCH) {
507 copy_v2_v2(min, marker->search_min);
508 copy_v2_v2(max, marker->search_max);
511 BKE_tracking_marker_pattern_minmax(marker, min, max);
514 min[0] -= padding / width;
515 min[1] -= padding / height;
516 max[0] += padding / width;
517 max[1] += padding / height;
520 crn[0] = marker->pos[0] + max[0];
521 crn[1] = marker->pos[1] + min[1];
524 crn[0] = marker->pos[0] + min[0];
525 crn[1] = marker->pos[1] + max[1];
528 return mouse_on_slide_zone(sc, marker, area, co, crn, padding, width, height);
531 static int get_mouse_pattern_corner(SpaceClip *sc, MovieTrackingMarker *marker, float co[2], int width, int height)
534 float len = FLT_MAX, dx, dy;
536 for (i = 0; i < 4; i++) {
541 cur_len = len_v2v2(marker->pattern_corners[i], marker->pattern_corners[next]);
543 len = min_ff(cur_len, len);
546 dx = 12.0f / width / sc->zoom;
547 dy = 12.0f / height / sc->zoom;
549 dx = min_ff(dx, len * 2.0f / 3.0f);
550 dy = min_ff(dy, len * width / height * 2.0f / 3.0f);
552 for (i = 0; i < 4; i++) {
556 add_v2_v2v2(crn, marker->pattern_corners[i], marker->pos);
558 inside = IN_RANGE_INCL(co[0], crn[0] - dx, crn[0] + dx) &&
559 IN_RANGE_INCL(co[1], crn[1] - dy, crn[1] + dy);
568 static int mouse_on_offset(SpaceClip *sc, MovieTrackingTrack *track, MovieTrackingMarker *marker,
569 float co[2], int width, int height)
571 float pos[2], dx, dy;
572 float pat_min[2], pat_max[2];
574 BKE_tracking_marker_pattern_minmax(marker, pat_min, pat_max);
576 add_v2_v2v2(pos, marker->pos, track->offset);
578 dx = 12.0f / width / sc->zoom;
579 dy = 12.0f / height / sc->zoom;
581 dx = min_ff(dx, (pat_max[0] - pat_min[0]) / 2.0f);
582 dy = min_ff(dy, (pat_max[1] - pat_min[1]) / 2.0f);
584 return co[0] >= pos[0] - dx && co[0] <= pos[0] + dx && co[1] >= pos[1] - dy && co[1] <= pos[1] + dy;
587 static int mouse_on_tilt(SpaceClip *sc, MovieTrackingMarker *marker, float co[2], int width, int height)
591 slide_marker_tilt_slider(marker, slider);
593 return mouse_on_slide_zone(sc, marker, TRACK_AREA_PAT, co, slider, 0.0f, width, height);
596 static bool slide_check_corners(float (*corners)[2])
600 float p[2] = {0.0f, 0.0f};
602 if (!isect_point_quad_v2(p, corners[0], corners[1], corners[2], corners[3]))
605 for (i = 0; i < 4; i++) {
606 float v1[2], v2[2], cur_cross;
609 prev = (4 + i - 1) % 4;
611 sub_v2_v2v2(v1, corners[i], corners[prev]);
612 sub_v2_v2v2(v2, corners[next], corners[i]);
614 cur_cross = cross_v2v2(v1, v2);
616 if (fabsf(cur_cross) > FLT_EPSILON) {
620 else if (cross * cur_cross < 0.0f) {
629 static void hide_cursor(bContext *C)
631 wmWindow *win = CTX_wm_window(C);
633 WM_cursor_set(win, CURSOR_NONE);
636 static void show_cursor(bContext *C)
638 wmWindow *win = CTX_wm_window(C);
640 WM_cursor_set(win, CURSOR_STD);
643 MovieTrackingTrack *tracking_marker_check_slide(bContext *C, const wmEvent *event, int *area_r, int *action_r, int *corner_r)
645 SpaceClip *sc = CTX_wm_space_clip(C);
646 ARegion *ar = CTX_wm_region(C);
648 MovieClip *clip = ED_space_clip_get_clip(sc);
649 MovieTrackingTrack *track;
652 ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
653 int framenr = ED_space_clip_get_clip_frame_number(sc);
654 int action = -1, area = 0, corner = -1;
656 ED_space_clip_get_size(sc, &width, &height);
658 if (width == 0 || height == 0)
661 ED_clip_mouse_pos(sc, ar, event->mval, co);
663 track = tracksbase->first;
665 if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) {
666 MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
669 if ((marker->flag & MARKER_DISABLED) == 0) {
670 if (mouse_on_offset(sc, track, marker, co, width, height)) {
671 area = TRACK_AREA_POINT;
672 action = SLIDE_ACTION_POS;
676 if (!ok && (sc->flag & SC_SHOW_MARKER_SEARCH)) {
677 if (mouse_on_corner(sc, marker, TRACK_AREA_SEARCH, co, 1, 0.0f, width, height)) {
678 area = TRACK_AREA_SEARCH;
679 action = SLIDE_ACTION_OFFSET;
682 else if (mouse_on_corner(sc, marker, TRACK_AREA_SEARCH, co, 0, 0.0f, width, height)) {
683 area = TRACK_AREA_SEARCH;
684 action = SLIDE_ACTION_SIZE;
689 if (!ok && (sc->flag & SC_SHOW_MARKER_PATTERN)) {
690 int current_corner = get_mouse_pattern_corner(sc, marker, co, width, height);
692 if (current_corner != -1) {
693 area = TRACK_AREA_PAT;
694 action = SLIDE_ACTION_POS;
695 corner = current_corner;
700 /* TODO: disable for now, needs better approaches for visualization */
702 if (mouse_on_corner(sc, marker, TRACK_AREA_PAT, co, 1, 12.0f, width, height)) {
703 area = TRACK_AREA_PAT;
704 action = SLIDE_ACTION_OFFSET;
707 if (!ok && mouse_on_corner(sc, marker, TRACK_AREA_PAT, co, 0, 12.0f, width, height)) {
708 area = TRACK_AREA_PAT;
709 action = SLIDE_ACTION_SIZE;
713 if (!ok && mouse_on_tilt(sc, marker, co, width, height)) {
714 area = TRACK_AREA_PAT;
715 action = SLIDE_ACTION_TILT_SIZE;
742 static void *slide_marker_customdata(bContext *C, const wmEvent *event)
744 SpaceClip *sc = CTX_wm_space_clip(C);
745 ARegion *ar = CTX_wm_region(C);
747 MovieTrackingTrack *track;
750 void *customdata = NULL;
751 int framenr = ED_space_clip_get_clip_frame_number(sc);
752 int area, action, corner;
754 ED_space_clip_get_size(sc, &width, &height);
756 if (width == 0 || height == 0)
759 ED_clip_mouse_pos(sc, ar, event->mval, co);
761 track = tracking_marker_check_slide(C, event, &area, &action, &corner);
763 MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
765 customdata = create_slide_marker_data(sc, track, marker, event, area, corner, action, width, height);
771 static int slide_marker_invoke(bContext *C, wmOperator *op, const wmEvent *event)
773 SlideMarkerData *slidedata = slide_marker_customdata(C, event);
776 SpaceClip *sc = CTX_wm_space_clip(C);
777 MovieClip *clip = ED_space_clip_get_clip(sc);
778 MovieTracking *tracking = &clip->tracking;
780 tracking->act_track = slidedata->track;
781 tracking->act_plane_track = NULL;
783 op->customdata = slidedata;
786 WM_event_add_modal_handler(C, op);
788 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
790 return OPERATOR_RUNNING_MODAL;
793 return OPERATOR_PASS_THROUGH;
796 static void cancel_mouse_slide(SlideMarkerData *data)
798 MovieTrackingTrack *track = data->track;
799 MovieTrackingMarker *marker = data->marker;
801 memcpy(marker->pattern_corners, data->old_corners, sizeof(marker->pattern_corners));
802 copy_v2_v2(marker->search_min, data->old_search_min);
803 copy_v2_v2(marker->search_max, data->old_search_max);
804 copy_v2_v2(marker->pos, data->old_pos);
805 copy_v2_v2(track->offset, data->old_offset);
807 if (data->old_markers) {
810 for (a = 0; a < data->track->markersnr; a++)
811 copy_v2_v2(data->track->markers[a].pos, data->old_markers[a]);
815 static void apply_mouse_slide(bContext *C, SlideMarkerData *data)
817 if (data->area == TRACK_AREA_POINT) {
818 SpaceClip *sc = CTX_wm_space_clip(C);
819 MovieClip *clip = ED_space_clip_get_clip(sc);
820 MovieTrackingPlaneTrack *plane_track;
821 ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking);
822 int framenr = ED_space_clip_get_clip_frame_number(sc);
824 for (plane_track = plane_tracks_base->first;
826 plane_track = plane_track->next)
828 if ((plane_track->flag & PLANE_TRACK_AUTOKEY) == 0) {
830 for (i = 0; i < plane_track->point_tracksnr; i++) {
831 if (plane_track->point_tracks[i] == data->track) {
832 BKE_tracking_track_plane_from_existing_motion(plane_track, framenr);
841 static void free_slide_data(SlideMarkerData *data)
843 if (data->old_markers)
844 MEM_freeN(data->old_markers);
849 static int slide_marker_modal(bContext *C, wmOperator *op, const wmEvent *event)
851 SpaceClip *sc = CTX_wm_space_clip(C);
852 ARegion *ar = CTX_wm_region(C);
854 SlideMarkerData *data = (SlideMarkerData *)op->customdata;
855 float dx, dy, mdelta[2];
857 switch (event->type) {
862 if (data->action == SLIDE_ACTION_SIZE)
863 if (ELEM(event->type, LEFTCTRLKEY, RIGHTCTRLKEY))
864 data->lock = event->val == KM_RELEASE;
866 if (ELEM(event->type, LEFTSHIFTKEY, RIGHTSHIFTKEY))
867 data->accurate = event->val == KM_PRESS;
871 mdelta[0] = event->mval[0] - data->mval[0];
872 mdelta[1] = event->mval[1] - data->mval[1];
874 dx = mdelta[0] / data->width / sc->zoom;
877 dy = -dx / data->height * data->width;
879 dy = mdelta[1] / data->height / sc->zoom;
881 if (data->accurate) {
886 if (data->area == TRACK_AREA_POINT) {
887 if (data->action == SLIDE_ACTION_OFFSET) {
888 data->offset[0] = data->old_offset[0] + dx;
889 data->offset[1] = data->old_offset[1] + dy;
892 data->pos[0] = data->old_pos[0] + dx;
893 data->pos[1] = data->old_pos[1] + dy;
896 WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
897 DAG_id_tag_update(&sc->clip->id, 0);
899 else if (data->area == TRACK_AREA_PAT) {
900 if (data->action == SLIDE_ACTION_SIZE) {
901 float start[2], end[2];
904 ED_clip_point_stable_pos(sc, ar, data->mval[0], data->mval[1], &start[0], &start[1]);
906 sub_v2_v2(start, data->old_pos);
908 if (len_v2(start) > 0.0f) {
911 if (data->accurate) {
912 mval[0] = data->mval[0] + (event->mval[0] - data->mval[0]) / 5.0f;
913 mval[1] = data->mval[1] + (event->mval[1] - data->mval[1]) / 5.0f;
916 mval[0] = event->mval[0];
917 mval[1] = event->mval[1];
920 ED_clip_point_stable_pos(sc, ar, mval[0], mval[1], &end[0], &end[1]);
922 sub_v2_v2(end, data->old_pos);
924 scale = len_v2(end) / len_v2(start);
929 for (a = 0; a < 4; a++) {
930 mul_v2_v2fl(data->corners[a], data->old_corners[a], scale);
935 BKE_tracking_marker_clamp(data->marker, CLAMP_PAT_DIM);
937 else if (data->action == SLIDE_ACTION_OFFSET) {
938 float d[2] = {dx, dy};
941 for (a = 0; a < data->track->markersnr; a++)
942 add_v2_v2v2(data->track->markers[a].pos, data->old_markers[a], d);
944 sub_v2_v2v2(data->offset, data->old_offset, d);
946 else if (data->action == SLIDE_ACTION_POS) {
949 copy_v2_v2(spos, data->pos);
951 data->pos[0] = data->spos[0] + dx;
952 data->pos[1] = data->spos[1] + dy;
954 if (!slide_check_corners(data->corners)) {
955 copy_v2_v2(data->pos, spos);
958 /* currently only patterns are allowed to have such combination of event and data */
959 BKE_tracking_marker_clamp(data->marker, CLAMP_PAT_DIM);
961 else if (data->action == SLIDE_ACTION_TILT_SIZE) {
962 float start[2], end[2];
963 float scale = 1.0f, angle = 0.0f;
967 if (data->accurate) {
968 mval[0] = data->mval[0] + (event->mval[0] - data->mval[0]) / 5.0f;
969 mval[1] = data->mval[1] + (event->mval[1] - data->mval[1]) / 5.0f;
972 mval[0] = event->mval[0];
973 mval[1] = event->mval[1];
976 sub_v2_v2v2(start, data->spos, data->old_pos);
978 ED_clip_point_stable_pos(sc, ar, mval[0], mval[1], &end[0], &end[1]);
979 sub_v2_v2(end, data->old_pos);
981 if (len_v2(start) > 0.0f) {
982 scale = len_v2(end) / len_v2(start);
989 angle = -angle_signed_v2v2(start, end);
991 for (a = 0; a < 4; a++) {
994 mul_v2_v2fl(data->corners[a], data->old_corners[a], scale);
996 copy_v2_v2(vec, data->corners[a]);
997 vec[0] *= data->width;
998 vec[1] *= data->height;
1000 data->corners[a][0] = (vec[0] * cosf(angle) - vec[1] * sinf(angle)) / data->width;
1001 data->corners[a][1] = (vec[1] * cosf(angle) + vec[0] * sinf(angle)) / data->height;
1004 BKE_tracking_marker_clamp(data->marker, CLAMP_PAT_DIM);
1008 else if (data->area == TRACK_AREA_SEARCH) {
1009 if (data->action == SLIDE_ACTION_SIZE) {
1010 data->min[0] = data->old_search_min[0] - dx;
1011 data->max[0] = data->old_search_max[0] + dx;
1013 data->min[1] = data->old_search_min[1] + dy;
1014 data->max[1] = data->old_search_max[1] - dy;
1016 BKE_tracking_marker_clamp(data->marker, CLAMP_SEARCH_DIM);
1018 else if (data->area == TRACK_AREA_SEARCH) {
1019 float d[2] = {dx, dy};
1021 add_v2_v2v2(data->min, data->old_search_min, d);
1022 add_v2_v2v2(data->max, data->old_search_max, d);
1025 BKE_tracking_marker_clamp(data->marker, CLAMP_SEARCH_POS);
1028 data->marker->flag &= ~MARKER_TRACKED;
1030 WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, NULL);
1035 if (event->val == KM_RELEASE) {
1036 apply_mouse_slide(C, op->customdata);
1037 free_slide_data(op->customdata);
1041 return OPERATOR_FINISHED;
1047 cancel_mouse_slide(op->customdata);
1049 free_slide_data(op->customdata);
1053 WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, NULL);
1055 return OPERATOR_CANCELLED;
1058 return OPERATOR_RUNNING_MODAL;
1061 void CLIP_OT_slide_marker(wmOperatorType *ot)
1064 ot->name = "Slide Marker";
1065 ot->description = "Slide marker areas";
1066 ot->idname = "CLIP_OT_slide_marker";
1069 ot->poll = ED_space_clip_tracking_poll;
1070 ot->invoke = slide_marker_invoke;
1071 ot->modal = slide_marker_modal;
1074 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_POINTER | OPTYPE_BLOCKING;
1077 RNA_def_float_vector(ot->srna, "offset", 2, NULL, -FLT_MAX, FLT_MAX,
1078 "Offset", "Offset in floating point units, 1.0 is the width and height of the image", -FLT_MAX, FLT_MAX);
1081 /********************** track operator *********************/
1083 typedef struct TrackMarkersJob {
1084 struct MovieTrackingContext *context; /* tracking context */
1085 int sfra, efra, lastfra; /* Start, end and recently tracked frames */
1086 int backwards; /* Backwards tracking flag */
1087 MovieClip *clip; /* Clip which is tracking */
1088 float delay; /* Delay in milliseconds to allow tracking at fixed FPS */
1091 struct Scene *scene;
1092 struct bScreen *screen;
1095 static int track_markers_testbreak(void)
1100 static int track_count_markers(SpaceClip *sc, MovieClip *clip)
1103 ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
1104 MovieTrackingTrack *track;
1105 int framenr = ED_space_clip_get_clip_frame_number(sc);
1107 track = tracksbase->first;
1109 if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) {
1110 MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
1112 if (!marker || (marker->flag & MARKER_DISABLED) == 0)
1116 track = track->next;
1122 static void clear_invisible_track_selection(SpaceClip *sc, MovieClip *clip)
1124 ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
1127 if ((sc->flag & SC_SHOW_MARKER_PATTERN) == 0)
1128 hidden |= TRACK_AREA_PAT;
1130 if ((sc->flag & SC_SHOW_MARKER_SEARCH) == 0)
1131 hidden |= TRACK_AREA_SEARCH;
1134 MovieTrackingTrack *track = tracksbase->first;
1137 if ((track->flag & TRACK_HIDDEN) == 0)
1138 BKE_tracking_track_flag_clear(track, hidden, SELECT);
1140 track = track->next;
1145 static void track_init_markers(SpaceClip *sc, MovieClip *clip, int *frames_limit_r)
1147 ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
1148 MovieTrackingTrack *track;
1149 int framenr = ED_space_clip_get_clip_frame_number(sc);
1150 int frames_limit = 0;
1152 clear_invisible_track_selection(sc, clip);
1154 track = tracksbase->first;
1156 if (TRACK_VIEW_SELECTED(sc, track)) {
1157 if ((track->flag & TRACK_HIDDEN) == 0 && (track->flag & TRACK_LOCKED) == 0) {
1158 BKE_tracking_marker_ensure(track, framenr);
1160 if (track->frames_limit) {
1161 if (frames_limit == 0)
1162 frames_limit = track->frames_limit;
1164 frames_limit = min_ii(frames_limit, (int)track->frames_limit);
1169 track = track->next;
1172 *frames_limit_r = frames_limit;
1175 static bool track_markers_check_direction(int backwards, int curfra, int efra)
1189 static int track_markers_initjob(bContext *C, TrackMarkersJob *tmj, int backwards)
1191 SpaceClip *sc = CTX_wm_space_clip(C);
1192 MovieClip *clip = ED_space_clip_get_clip(sc);
1193 Scene *scene = CTX_data_scene(C);
1194 MovieTrackingSettings *settings = &clip->tracking.settings;
1197 track_init_markers(sc, clip, &frames_limit);
1199 tmj->sfra = ED_space_clip_get_clip_frame_number(sc);
1201 tmj->backwards = backwards;
1208 /* limit frames to be tracked by user setting */
1211 tmj->efra = MAX2(tmj->efra, tmj->sfra - frames_limit);
1213 tmj->efra = MIN2(tmj->efra, tmj->sfra + frames_limit);
1216 tmj->efra = BKE_movieclip_remap_scene_to_clip_frame(clip, tmj->efra);
1218 if (settings->speed != TRACKING_SPEED_FASTEST) {
1219 tmj->delay = 1.0f / scene->r.frs_sec * 1000.0f;
1221 if (settings->speed == TRACKING_SPEED_HALF)
1223 else if (settings->speed == TRACKING_SPEED_QUARTER)
1225 else if (settings->speed == TRACKING_SPEED_DOUBLE)
1229 tmj->context = BKE_tracking_context_new(clip, &sc->user, backwards, 1);
1231 clip->tracking_context = tmj->context;
1233 tmj->lastfra = tmj->sfra;
1235 /* XXX: silly to store this, but this data is needed to update scene and movie-clip
1236 * frame numbers when tracking is finished. This introduces better feedback for artists.
1237 * Maybe there's another way to solve this problem, but can't think better way atm.
1238 * Anyway, this way isn't more unstable as animation rendering animation
1239 * which uses the same approach (except storing screen). */
1241 tmj->main = CTX_data_main(C);
1242 tmj->screen = CTX_wm_screen(C);
1244 return track_markers_check_direction(backwards, tmj->sfra, tmj->efra);
1247 static void track_markers_startjob(void *tmv, short *stop, short *do_update, float *progress)
1249 TrackMarkersJob *tmj = (TrackMarkersJob *)tmv;
1250 int framenr = tmj->sfra;
1251 // double t = PIL_check_seconds_timer();
1253 while (framenr != tmj->efra) {
1254 if (tmj->delay > 0) {
1255 /* tracking should happen with fixed fps. Calculate time
1256 * using current timer value before tracking frame and after.
1258 * Small (and maybe unneeded optimization): do not calculate exec_time
1259 * for "Fastest" tracking */
1261 double start_time = PIL_check_seconds_timer(), exec_time;
1263 if (!BKE_tracking_context_step(tmj->context))
1266 exec_time = PIL_check_seconds_timer() - start_time;
1267 if (tmj->delay > (float)exec_time)
1268 PIL_sleep_ms(tmj->delay - (float)exec_time);
1270 else if (!BKE_tracking_context_step(tmj->context))
1274 *progress = (float)(framenr - tmj->sfra) / (tmj->efra - tmj->sfra);
1281 tmj->lastfra = framenr;
1283 if (*stop || track_markers_testbreak())
1287 // printf("Tracking time: %lf\n", PIL_check_seconds_timer()-t);
1290 static void track_markers_updatejob(void *tmv)
1292 TrackMarkersJob *tmj = (TrackMarkersJob *)tmv;
1294 BKE_tracking_context_sync(tmj->context);
1297 static void track_markers_endjob(void *tmv)
1299 TrackMarkersJob *tmj = (TrackMarkersJob *)tmv;
1301 tmj->clip->tracking_context = NULL;
1302 tmj->scene->r.cfra = BKE_movieclip_remap_clip_to_scene_frame(tmj->clip, tmj->lastfra);
1303 ED_update_for_newframe(tmj->main, tmj->scene, 0);
1305 BKE_tracking_context_sync(tmj->context);
1306 BKE_tracking_context_finish(tmj->context);
1308 WM_main_add_notifier(NC_SCENE | ND_FRAME, tmj->scene);
1311 static void track_markers_freejob(void *tmv)
1313 TrackMarkersJob *tmj = (TrackMarkersJob *)tmv;
1314 BKE_tracking_context_free(tmj->context);
1318 static int track_markers_exec(bContext *C, wmOperator *op)
1320 SpaceClip *sc = CTX_wm_space_clip(C);
1321 MovieClip *clip = ED_space_clip_get_clip(sc);
1322 Scene *scene = CTX_data_scene(C);
1323 struct MovieTrackingContext *context;
1324 int framenr = ED_space_clip_get_clip_frame_number(sc);
1325 int sfra = framenr, efra;
1326 int backwards = RNA_boolean_get(op->ptr, "backwards");
1327 int sequence = RNA_boolean_get(op->ptr, "sequence");
1330 if (track_count_markers(sc, clip) == 0)
1331 return OPERATOR_CANCELLED;
1333 track_init_markers(sc, clip, &frames_limit);
1340 /* limit frames to be tracked by user setting */
1343 efra = MAX2(efra, sfra - frames_limit);
1345 efra = MIN2(efra, sfra + frames_limit);
1348 efra = BKE_movieclip_remap_scene_to_clip_frame(clip, efra);
1350 if (!track_markers_check_direction(backwards, framenr, efra))
1351 return OPERATOR_CANCELLED;
1353 /* do not disable tracks due to threshold when tracking frame-by-frame */
1354 context = BKE_tracking_context_new(clip, &sc->user, backwards, sequence);
1356 while (framenr != efra) {
1357 if (!BKE_tracking_context_step(context))
1360 if (backwards) framenr--;
1367 BKE_tracking_context_sync(context);
1368 BKE_tracking_context_finish(context);
1369 BKE_tracking_context_free(context);
1371 /* update scene current frame to the lastes tracked frame */
1372 scene->r.cfra = BKE_movieclip_remap_clip_to_scene_frame(clip, framenr);
1374 WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
1375 WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
1377 return OPERATOR_FINISHED;
1380 static int track_markers_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
1382 TrackMarkersJob *tmj;
1383 ScrArea *sa = CTX_wm_area(C);
1384 SpaceClip *sc = CTX_wm_space_clip(C);
1385 MovieClip *clip = ED_space_clip_get_clip(sc);
1387 int backwards = RNA_boolean_get(op->ptr, "backwards");
1388 int sequence = RNA_boolean_get(op->ptr, "sequence");
1390 if (WM_jobs_test(CTX_wm_manager(C), CTX_wm_area(C), WM_JOB_TYPE_ANY)) {
1391 /* only one tracking is allowed at a time */
1392 return OPERATOR_CANCELLED;
1395 if (clip->tracking_context)
1396 return OPERATOR_CANCELLED;
1398 if (track_count_markers(sc, clip) == 0)
1399 return OPERATOR_CANCELLED;
1402 return track_markers_exec(C, op);
1404 tmj = MEM_callocN(sizeof(TrackMarkersJob), "TrackMarkersJob data");
1405 if (!track_markers_initjob(C, tmj, backwards)) {
1406 track_markers_freejob(tmj);
1408 return OPERATOR_CANCELLED;
1412 wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), sa, "Track Markers",
1413 WM_JOB_PROGRESS, WM_JOB_TYPE_CLIP_TRACK_MARKERS);
1414 WM_jobs_customdata_set(wm_job, tmj, track_markers_freejob);
1416 /* if there's delay set in tracking job, tracking should happen
1417 * with fixed FPS. To deal with editor refresh we have to synchronize
1418 * tracks from job and tracks in clip. Do this in timer callback
1419 * to prevent threading conflicts. */
1421 WM_jobs_timer(wm_job, tmj->delay / 1000.0f, NC_MOVIECLIP | NA_EVALUATED, 0);
1423 WM_jobs_timer(wm_job, 0.2, NC_MOVIECLIP | NA_EVALUATED, 0);
1425 WM_jobs_callbacks(wm_job, track_markers_startjob, NULL, track_markers_updatejob, track_markers_endjob);
1429 WM_jobs_start(CTX_wm_manager(C), wm_job);
1432 /* add modal handler for ESC */
1433 WM_event_add_modal_handler(C, op);
1435 return OPERATOR_RUNNING_MODAL;
1438 static int track_markers_modal(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
1440 /* no running tracking, remove handler and pass through */
1441 if (0 == WM_jobs_test(CTX_wm_manager(C), CTX_wm_area(C), WM_JOB_TYPE_ANY))
1442 return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
1444 /* running tracking */
1445 switch (event->type) {
1447 return OPERATOR_RUNNING_MODAL;
1451 return OPERATOR_PASS_THROUGH;
1454 void CLIP_OT_track_markers(wmOperatorType *ot)
1457 ot->name = "Track Markers";
1458 ot->description = "Track selected markers";
1459 ot->idname = "CLIP_OT_track_markers";
1462 ot->exec = track_markers_exec;
1463 ot->invoke = track_markers_invoke;
1464 ot->poll = ED_space_clip_tracking_poll;
1465 ot->modal = track_markers_modal;
1468 ot->flag = OPTYPE_UNDO;
1471 RNA_def_boolean(ot->srna, "backwards", 0, "Backwards", "Do backwards tracking");
1472 RNA_def_boolean(ot->srna, "sequence", 0, "Track Sequence", "Track marker during image sequence rather than single image");
1475 /********************** refine track position operator *********************/
1477 static int refine_marker_exec(bContext *C, wmOperator *op)
1479 SpaceClip *sc = CTX_wm_space_clip(C);
1480 MovieClip *clip = ED_space_clip_get_clip(sc);
1481 MovieTracking *tracking = &clip->tracking;
1482 ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
1483 MovieTrackingTrack *track;
1484 bool backwards = RNA_boolean_get(op->ptr, "backwards");
1485 int framenr = ED_space_clip_get_clip_frame_number(sc);
1487 for (track = tracksbase->first; track; track = track->next) {
1488 if (TRACK_VIEW_SELECTED(sc, track)) {
1489 MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
1491 BKE_tracking_refine_marker(clip, track, marker, backwards);
1495 WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
1497 return OPERATOR_FINISHED;
1500 void CLIP_OT_refine_markers(wmOperatorType *ot)
1503 ot->name = "Refine Markers";
1504 ot->description = "Refine selected markers positions "
1505 "by running the tracker from track's reference to current frame";
1506 ot->idname = "CLIP_OT_refine_markers";
1509 ot->exec = refine_marker_exec;
1510 ot->poll = ED_space_clip_tracking_poll;
1513 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1516 RNA_def_boolean(ot->srna, "backwards", 0, "Backwards", "Do backwards tracking");
1519 /********************** solve camera operator *********************/
1526 ReportList *reports;
1528 char stats_message[256];
1530 struct MovieReconstructContext *context;
1533 static int solve_camera_initjob(bContext *C, SolveCameraJob *scj, wmOperator *op, char *error_msg, int max_error)
1535 SpaceClip *sc = CTX_wm_space_clip(C);
1536 MovieClip *clip = ED_space_clip_get_clip(sc);
1537 Scene *scene = CTX_data_scene(C);
1538 MovieTracking *tracking = &clip->tracking;
1539 MovieTrackingObject *object = BKE_tracking_object_get_active(tracking);
1542 if (!BKE_tracking_reconstruction_check(tracking, object, error_msg, max_error))
1545 /* could fail if footage uses images with different sizes */
1546 BKE_movieclip_get_size(clip, &sc->user, &width, &height);
1550 scj->reports = op->reports;
1551 scj->user = sc->user;
1553 scj->context = BKE_tracking_reconstruction_context_new(tracking, object,
1554 object->keyframe1, object->keyframe2, width, height);
1556 tracking->stats = MEM_callocN(sizeof(MovieTrackingStats), "solve camera stats");
1561 static void solve_camera_updatejob(void *scv)
1563 SolveCameraJob *scj = (SolveCameraJob *)scv;
1564 MovieTracking *tracking = &scj->clip->tracking;
1566 BLI_strncpy(tracking->stats->message, scj->stats_message, sizeof(tracking->stats->message));
1569 static void solve_camera_startjob(void *scv, short *stop, short *do_update, float *progress)
1571 SolveCameraJob *scj = (SolveCameraJob *)scv;
1573 BKE_tracking_reconstruction_solve(scj->context, stop, do_update, progress,
1574 scj->stats_message, sizeof(scj->stats_message));
1577 static void solve_camera_freejob(void *scv)
1579 SolveCameraJob *scj = (SolveCameraJob *)scv;
1580 MovieTracking *tracking = &scj->clip->tracking;
1581 Scene *scene = scj->scene;
1582 MovieClip *clip = scj->clip;
1585 if (!scj->context) {
1586 /* job weren't fully initialized due to some error */
1591 solved = BKE_tracking_reconstruction_finish(scj->context, tracking);
1593 BKE_report(scj->reports, RPT_WARNING, "Some data failed to reconstruct (see console for details)");
1595 BKE_reportf(scj->reports, RPT_INFO, "Average re-projection error: %.3f", tracking->reconstruction.error);
1597 /* set currently solved clip as active for scene */
1599 id_us_min(&clip->id);
1602 id_us_plus(&clip->id);
1604 /* set blender camera focal length so result would look fine there */
1605 if (scene->camera && scene->camera->data && GS(((ID *) scene->camera->data)->name) == ID_CA) {
1606 Camera *camera = (Camera *)scene->camera->data;
1609 BKE_movieclip_get_size(clip, &scj->user, &width, &height);
1611 BKE_tracking_camera_to_blender(tracking, scene, camera, width, height);
1613 WM_main_add_notifier(NC_OBJECT, camera);
1616 MEM_freeN(tracking->stats);
1617 tracking->stats = NULL;
1619 DAG_id_tag_update(&clip->id, 0);
1621 WM_main_add_notifier(NC_MOVIECLIP | NA_EVALUATED, clip);
1622 WM_main_add_notifier(NC_OBJECT | ND_TRANSFORM, NULL);
1624 /* update active clip displayed in scene buttons */
1625 WM_main_add_notifier(NC_SCENE, scene);
1627 BKE_tracking_reconstruction_context_free(scj->context);
1631 static int solve_camera_exec(bContext *C, wmOperator *op)
1633 SolveCameraJob *scj;
1634 char error_msg[256] = "\0";
1636 scj = MEM_callocN(sizeof(SolveCameraJob), "SolveCameraJob data");
1637 if (!solve_camera_initjob(C, scj, op, error_msg, sizeof(error_msg))) {
1639 BKE_report(op->reports, RPT_ERROR, error_msg);
1641 solve_camera_freejob(scj);
1643 return OPERATOR_CANCELLED;
1646 solve_camera_startjob(scj, NULL, NULL, NULL);
1648 solve_camera_freejob(scj);
1650 return OPERATOR_FINISHED;
1653 static int solve_camera_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
1655 SolveCameraJob *scj;
1656 ScrArea *sa = CTX_wm_area(C);
1657 SpaceClip *sc = CTX_wm_space_clip(C);
1658 MovieClip *clip = ED_space_clip_get_clip(sc);
1659 MovieTracking *tracking = &clip->tracking;
1660 MovieTrackingReconstruction *reconstruction = BKE_tracking_get_active_reconstruction(tracking);
1662 char error_msg[256] = "\0";
1664 if (WM_jobs_test(CTX_wm_manager(C), CTX_wm_area(C), WM_JOB_TYPE_ANY)) {
1665 /* only one solve is allowed at a time */
1666 return OPERATOR_CANCELLED;
1669 scj = MEM_callocN(sizeof(SolveCameraJob), "SolveCameraJob data");
1670 if (!solve_camera_initjob(C, scj, op, error_msg, sizeof(error_msg))) {
1672 BKE_report(op->reports, RPT_ERROR, error_msg);
1674 solve_camera_freejob(scj);
1676 return OPERATOR_CANCELLED;
1679 BLI_strncpy(tracking->stats->message, "Solving camera | Preparing solve", sizeof(tracking->stats->message));
1681 /* hide reconstruction statistics from previous solve */
1682 reconstruction->flag &= ~TRACKING_RECONSTRUCTED;
1683 WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
1686 wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), sa, "Solve Camera",
1687 WM_JOB_PROGRESS, WM_JOB_TYPE_CLIP_SOLVE_CAMERA);
1688 WM_jobs_customdata_set(wm_job, scj, solve_camera_freejob);
1689 WM_jobs_timer(wm_job, 0.1, NC_MOVIECLIP | NA_EVALUATED, 0);
1690 WM_jobs_callbacks(wm_job, solve_camera_startjob, NULL, solve_camera_updatejob, NULL);
1694 WM_jobs_start(CTX_wm_manager(C), wm_job);
1697 /* add modal handler for ESC */
1698 WM_event_add_modal_handler(C, op);
1700 return OPERATOR_RUNNING_MODAL;
1703 static int solve_camera_modal(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
1705 /* no running solver, remove handler and pass through */
1706 if (0 == WM_jobs_test(CTX_wm_manager(C), CTX_wm_area(C), WM_JOB_TYPE_ANY))
1707 return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
1709 /* running tracking */
1710 switch (event->type) {
1712 return OPERATOR_RUNNING_MODAL;
1716 return OPERATOR_PASS_THROUGH;
1719 void CLIP_OT_solve_camera(wmOperatorType *ot)
1722 ot->name = "Solve Camera";
1723 ot->description = "Solve camera motion from tracks";
1724 ot->idname = "CLIP_OT_solve_camera";
1727 ot->exec = solve_camera_exec;
1728 ot->invoke = solve_camera_invoke;
1729 ot->modal = solve_camera_modal;
1730 ot->poll = ED_space_clip_tracking_poll;
1733 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1736 /********************** clear solution operator *********************/
1738 static int clear_solution_exec(bContext *C, wmOperator *UNUSED(op))
1740 SpaceClip *sc = CTX_wm_space_clip(C);
1741 MovieClip *clip = ED_space_clip_get_clip(sc);
1742 MovieTracking *tracking = &clip->tracking;
1743 ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
1744 MovieTrackingReconstruction *reconstruction = BKE_tracking_get_active_reconstruction(tracking);
1745 MovieTrackingTrack *track = tracksbase->first;
1748 track->flag &= ~TRACK_HAS_BUNDLE;
1750 track = track->next;
1753 if (reconstruction->cameras)
1754 MEM_freeN(reconstruction->cameras);
1756 reconstruction->cameras = NULL;
1757 reconstruction->camnr = 0;
1759 reconstruction->flag &= ~TRACKING_RECONSTRUCTED;
1761 DAG_id_tag_update(&clip->id, 0);
1763 WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
1764 WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
1766 return OPERATOR_FINISHED;
1769 void CLIP_OT_clear_solution(wmOperatorType *ot)
1772 ot->name = "Clear Solution";
1773 ot->description = "Clear all calculated data";
1774 ot->idname = "CLIP_OT_clear_solution";
1777 ot->exec = clear_solution_exec;
1778 ot->poll = ED_space_clip_tracking_poll;
1781 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1784 /********************** clear track operator *********************/
1786 static int clear_track_path_exec(bContext *C, wmOperator *op)
1788 SpaceClip *sc = CTX_wm_space_clip(C);
1789 MovieClip *clip = ED_space_clip_get_clip(sc);
1790 MovieTracking *tracking = &clip->tracking;
1791 MovieTrackingTrack *track;
1792 ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
1793 int action = RNA_enum_get(op->ptr, "action");
1794 int clear_active = RNA_boolean_get(op->ptr, "clear_active");
1795 int framenr = ED_space_clip_get_clip_frame_number(sc);
1798 track = BKE_tracking_track_get_active(tracking);
1800 BKE_tracking_track_path_clear(track, framenr, action);
1804 track = tracksbase->first;
1806 if (TRACK_VIEW_SELECTED(sc, track))
1807 BKE_tracking_track_path_clear(track, framenr, action);
1809 track = track->next;
1813 BKE_tracking_dopesheet_tag_update(tracking);
1814 WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
1816 return OPERATOR_FINISHED;
1819 void CLIP_OT_clear_track_path(wmOperatorType *ot)
1821 static EnumPropertyItem clear_path_actions[] = {
1822 {TRACK_CLEAR_UPTO, "UPTO", 0, "Clear up-to", "Clear path up to current frame"},
1823 {TRACK_CLEAR_REMAINED, "REMAINED", 0, "Clear remained", "Clear path at remaining frames (after current)"},
1824 {TRACK_CLEAR_ALL, "ALL", 0, "Clear all", "Clear the whole path"},
1825 {0, NULL, 0, NULL, NULL}
1829 ot->name = "Clear Track Path";
1830 ot->description = "Clear tracks after/before current position or clear the whole track";
1831 ot->idname = "CLIP_OT_clear_track_path";
1834 ot->exec = clear_track_path_exec;
1835 ot->poll = ED_space_clip_tracking_poll;
1838 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1841 RNA_def_enum(ot->srna, "action", clear_path_actions, TRACK_CLEAR_REMAINED, "Action", "Clear action to execute");
1842 RNA_def_boolean(ot->srna, "clear_active", 0, "Clear Active", "Clear active track only instead of all selected tracks");
1845 /********************** disable markers operator *********************/
1847 static int disable_markers_exec(bContext *C, wmOperator *op)
1849 SpaceClip *sc = CTX_wm_space_clip(C);
1850 MovieClip *clip = ED_space_clip_get_clip(sc);
1851 MovieTracking *tracking = &clip->tracking;
1852 ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
1853 MovieTrackingTrack *track = tracksbase->first;
1854 int action = RNA_enum_get(op->ptr, "action");
1855 int framenr = ED_space_clip_get_clip_frame_number(sc);
1858 if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) {
1859 MovieTrackingMarker *marker = BKE_tracking_marker_ensure(track, framenr);
1862 marker->flag |= MARKER_DISABLED;
1863 else if (action == 1)
1864 marker->flag &= ~MARKER_DISABLED;
1865 else marker->flag ^= MARKER_DISABLED;
1868 track = track->next;
1871 DAG_id_tag_update(&clip->id, 0);
1873 WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
1875 return OPERATOR_FINISHED;
1878 void CLIP_OT_disable_markers(wmOperatorType *ot)
1880 static EnumPropertyItem actions_items[] = {
1881 {0, "DISABLE", 0, "Disable", "Disable selected markers"},
1882 {1, "ENABLE", 0, "Enable", "Enable selected markers"},
1883 {2, "TOGGLE", 0, "Toggle", "Toggle disabled flag for selected markers"},
1884 {0, NULL, 0, NULL, NULL}
1888 ot->name = "Disable Markers";
1889 ot->description = "Disable/enable selected markers";
1890 ot->idname = "CLIP_OT_disable_markers";
1893 ot->exec = disable_markers_exec;
1894 ot->poll = ED_space_clip_tracking_poll;
1897 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1900 RNA_def_enum(ot->srna, "action", actions_items, 0, "Action", "Disable action to execute");
1903 /********************** set origin operator *********************/
1905 static Object *get_camera_with_movieclip(Scene *scene, MovieClip *clip)
1907 Object *camera = scene->camera;
1910 if (camera && BKE_object_movieclip_get(scene, camera, false) == clip)
1913 base = scene->base.first;
1915 if (base->object->type == OB_CAMERA) {
1916 if (BKE_object_movieclip_get(scene, base->object, false) == clip) {
1917 camera = base->object;
1928 static Object *get_orientation_object(bContext *C)
1930 Scene *scene = CTX_data_scene(C);
1931 SpaceClip *sc = CTX_wm_space_clip(C);
1932 MovieClip *clip = ED_space_clip_get_clip(sc);
1933 MovieTracking *tracking = &clip->tracking;
1934 MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(tracking);
1935 Object *object = NULL;
1937 if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
1938 object = get_camera_with_movieclip(scene, clip);
1944 if (object && object->parent)
1945 object = object->parent;
1950 static int set_orientation_poll(bContext *C)
1952 SpaceClip *sc = CTX_wm_space_clip(C);
1955 Scene *scene = CTX_data_scene(C);
1956 MovieClip *clip = ED_space_clip_get_clip(sc);
1959 MovieTracking *tracking = &clip->tracking;
1960 MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(tracking);
1962 if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
1966 return OBACT != NULL;
1974 static int count_selected_bundles(bContext *C)
1976 SpaceClip *sc = CTX_wm_space_clip(C);
1977 MovieClip *clip = ED_space_clip_get_clip(sc);
1978 ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
1979 MovieTrackingTrack *track;
1982 track = tracksbase->first;
1984 if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_HAS_BUNDLE))
1987 track = track->next;
1993 static void object_solver_inverted_matrix(Scene *scene, Object *ob, float invmat[4][4])
1998 for (con = ob->constraints.first; con; con = con->next) {
1999 bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con);
2004 if (cti->type == CONSTRAINT_TYPE_OBJECTSOLVER) {
2005 bObjectSolverConstraint *data = (bObjectSolverConstraint *)con->data;
2008 Object *cam = data->camera ? data->camera : scene->camera;
2010 BKE_object_where_is_calc_mat4(scene, cam, invmat);
2013 mul_m4_m4m4(invmat, invmat, data->invmat);
2025 static Object *object_solver_camera(Scene *scene, Object *ob)
2029 for (con = ob->constraints.first; con; con = con->next) {
2030 bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con);
2035 if (cti->type == CONSTRAINT_TYPE_OBJECTSOLVER) {
2036 bObjectSolverConstraint *data = (bObjectSolverConstraint *)con->data;
2038 return data->camera ? data->camera : scene->camera;
2045 static int set_origin_exec(bContext *C, wmOperator *op)
2047 SpaceClip *sc = CTX_wm_space_clip(C);
2048 MovieClip *clip = ED_space_clip_get_clip(sc);
2049 MovieTracking *tracking = &clip->tracking;
2050 MovieTrackingTrack *track;
2051 MovieTrackingObject *tracking_object;
2052 Scene *scene = CTX_data_scene(C);
2054 Object *camera = get_camera_with_movieclip(scene, clip);
2055 ListBase *tracksbase;
2056 float mat[4][4], vec[3], median[3];
2057 int selected_count = count_selected_bundles(C);
2059 if (selected_count == 0) {
2060 BKE_report(op->reports, RPT_ERROR,
2061 "At least one track with bundle should be selected to define origin position");
2063 return OPERATOR_CANCELLED;
2066 object = get_orientation_object(C);
2068 BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
2070 return OPERATOR_CANCELLED;
2073 tracking_object = BKE_tracking_object_get_active(tracking);
2075 tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object);
2077 track = tracksbase->first;
2080 if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_HAS_BUNDLE)) {
2081 add_v3_v3(median, track->bundle_pos);
2084 track = track->next;
2086 mul_v3_fl(median, 1.0f / selected_count);
2088 BKE_tracking_get_camera_object_matrix(scene, camera, mat);
2090 mul_v3_m4v3(vec, mat, median);
2092 if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
2093 sub_v3_v3(object->loc, vec);
2096 object_solver_inverted_matrix(scene, object, mat);
2097 mul_v3_m4v3(vec, mat, vec);
2098 copy_v3_v3(object->loc, vec);
2101 DAG_id_tag_update(&clip->id, 0);
2102 DAG_id_tag_update(&object->id, OB_RECALC_OB);
2104 WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
2105 WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
2107 return OPERATOR_FINISHED;
2110 void CLIP_OT_set_origin(wmOperatorType *ot)
2113 ot->name = "Set Origin";
2114 ot->description = "Set active marker as origin by moving camera (or it's parent if present) in 3D space";
2115 ot->idname = "CLIP_OT_set_origin";
2118 ot->exec = set_origin_exec;
2119 ot->poll = set_orientation_poll;
2122 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2125 RNA_def_boolean(ot->srna, "use_median", 0, "Use Median", "Set origin to median point of selected bundles");
2128 /********************** set floor operator *********************/
2130 static void set_axis(Scene *scene, Object *ob, MovieClip *clip, MovieTrackingObject *tracking_object,
2131 MovieTrackingTrack *track, char axis)
2133 Object *camera = get_camera_with_movieclip(scene, clip);
2134 int is_camera = tracking_object->flag & TRACKING_OBJECT_CAMERA;
2136 float mat[4][4], vec[3], obmat[4][4], dvec[3];
2138 BKE_object_to_mat4(ob, obmat);
2140 BKE_tracking_get_camera_object_matrix(scene, camera, mat);
2141 mul_v3_m4v3(vec, mat, track->bundle_pos);
2142 copy_v3_v3(dvec, vec);
2147 object_solver_inverted_matrix(scene, ob, imat);
2148 mul_v3_m4v3(vec, imat, vec);
2150 invert_m4_m4(imat, obmat);
2151 mul_v3_m4v3(dvec, imat, vec);
2153 sub_v3_v3(vec, obmat[3]);
2156 if (len_v2(vec) < 1e-3f)
2162 if (fabsf(dvec[1]) < 1e-3f) {
2165 mat[0][0] = -1.0f; mat[0][1] = 0.0f; mat[0][2] = 0.0f;
2166 mat[1][0] = 0.0f; mat[1][1] = -1.0f; mat[1][2] = 0.0f;
2167 mat[2][0] = 0.0f; mat[2][1] = 0.0f; mat[2][2] = 1.0f;
2170 copy_v3_v3(mat[0], vec);
2172 if (is_camera || fabsf(vec[2]) < 1e-3f) {
2174 mat[2][0] = 0.0f; mat[2][1] = 0.0f; mat[2][2] = 1.0f;
2175 cross_v3_v3v3(mat[1], mat[2], mat[0]);
2180 cross_v3_v3v3(mat[1], mat[0], vec);
2181 cross_v3_v3v3(mat[2], mat[0], mat[1]);
2186 if (fabsf(dvec[0]) < 1e-3f) {
2189 mat[0][0] = -1.0f; mat[0][1] = 0.0f; mat[0][2] = 0.0f;
2190 mat[1][0] = 0.0f; mat[1][1] = -1.0f; mat[1][2] = 0.0f;
2191 mat[2][0] = 0.0f; mat[2][1] = 0.0f; mat[2][2] = 1.0f;
2194 copy_v3_v3(mat[1], vec);
2196 if (is_camera || fabsf(vec[2]) < 1e-3f) {
2198 mat[2][0] = 0.0f; mat[2][1] = 0.0f; mat[2][2] = 1.0f;
2199 cross_v3_v3v3(mat[0], mat[1], mat[2]);
2204 cross_v3_v3v3(mat[0], vec, mat[1]);
2205 cross_v3_v3v3(mat[2], mat[0], mat[1]);
2210 normalize_v3(mat[0]);
2211 normalize_v3(mat[1]);
2212 normalize_v3(mat[2]);
2217 mul_m4_m4m4(mat, mat, obmat);
2221 float lmat[4][4], ilmat[4][4], rmat[3][3];
2223 BKE_object_rot_to_mat3(ob, rmat, TRUE);
2225 mul_m4_m4m3(mat, mat, rmat);
2228 copy_v3_v3(lmat[3], obmat[3]);
2229 invert_m4_m4(ilmat, lmat);
2231 mul_serie_m4(mat, lmat, mat, ilmat, obmat, NULL, NULL, NULL, NULL);
2234 mul_m4_m4m4(mat, obmat, mat);
2238 BKE_object_apply_mat4(ob, mat, 0, 0);
2241 static int set_plane_exec(bContext *C, wmOperator *op)
2243 SpaceClip *sc = CTX_wm_space_clip(C);
2244 MovieClip *clip = ED_space_clip_get_clip(sc);
2245 Scene *scene = CTX_data_scene(C);
2246 MovieTracking *tracking = &clip->tracking;
2247 MovieTrackingObject *tracking_object;
2248 MovieTrackingTrack *track, *axis_track = NULL, *act_track;
2249 ListBase *tracksbase;
2251 Object *camera = get_camera_with_movieclip(scene, clip);
2253 float vec[3][3], mat[4][4], obmat[4][4], newmat[4][4], orig[3] = {0.0f, 0.0f, 0.0f};
2254 int plane = RNA_enum_get(op->ptr, "plane");
2255 float rot[4][4] = {{0.0f, 0.0f, -1.0f, 0.0f},
2256 {0.0f, 1.0f, 0.0f, 0.0f},
2257 {1.0f, 0.0f, 0.0f, 0.0f},
2258 {0.0f, 0.0f, 0.0f, 1.0f}}; /* 90 degrees Y-axis rotation matrix */
2260 if (count_selected_bundles(C) != 3) {
2261 BKE_report(op->reports, RPT_ERROR, "Three tracks with bundles are needed to orient the floor");
2263 return OPERATOR_CANCELLED;
2266 tracking_object = BKE_tracking_object_get_active(tracking);
2267 tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object);
2268 act_track = BKE_tracking_track_get_active(tracking);
2270 object = get_orientation_object(C);
2272 BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
2274 return OPERATOR_CANCELLED;
2277 BKE_tracking_get_camera_object_matrix(scene, camera, mat);
2279 /* get 3 bundles to use as reference */
2280 track = tracksbase->first;
2281 while (track && tot < 3) {
2282 if (track->flag & TRACK_HAS_BUNDLE && TRACK_VIEW_SELECTED(sc, track)) {
2283 mul_v3_m4v3(vec[tot], mat, track->bundle_pos);
2285 if (tot == 0 || track == act_track)
2286 copy_v3_v3(orig, vec[tot]);
2293 track = track->next;
2296 sub_v3_v3(vec[1], vec[0]);
2297 sub_v3_v3(vec[2], vec[0]);
2299 /* construct ortho-normal basis */
2302 if (plane == 0) { /* floor */
2303 cross_v3_v3v3(mat[0], vec[1], vec[2]);
2304 copy_v3_v3(mat[1], vec[1]);
2305 cross_v3_v3v3(mat[2], mat[0], mat[1]);
2307 else if (plane == 1) { /* wall */
2308 cross_v3_v3v3(mat[2], vec[1], vec[2]);
2309 copy_v3_v3(mat[1], vec[1]);
2310 cross_v3_v3v3(mat[0], mat[1], mat[2]);
2313 normalize_v3(mat[0]);
2314 normalize_v3(mat[1]);
2315 normalize_v3(mat[2]);
2317 /* move to origin point */
2318 mat[3][0] = orig[0];
2319 mat[3][1] = orig[1];
2320 mat[3][2] = orig[2];
2322 if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
2325 BKE_object_to_mat4(object, obmat);
2326 mul_m4_m4m4(mat, mat, obmat);
2327 mul_m4_m4m4(newmat, rot, mat);
2328 BKE_object_apply_mat4(object, newmat, 0, 0);
2330 /* make camera have positive z-coordinate */
2331 if (object->loc[2] < 0) {
2333 mul_m4_m4m4(newmat, rot, mat);
2334 BKE_object_apply_mat4(object, newmat, 0, 0);
2338 BKE_object_apply_mat4(object, mat, 0, 0);
2341 BKE_object_where_is_calc(scene, object);
2342 set_axis(scene, object, clip, tracking_object, axis_track, 'X');
2344 DAG_id_tag_update(&clip->id, 0);
2345 DAG_id_tag_update(&object->id, OB_RECALC_OB);
2347 WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
2348 WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
2350 return OPERATOR_FINISHED;
2353 void CLIP_OT_set_plane(wmOperatorType *ot)
2355 static EnumPropertyItem plane_items[] = {
2356 {0, "FLOOR", 0, "Floor", "Set floor plane"},
2357 {1, "WALL", 0, "Wall", "Set wall plane"},
2358 {0, NULL, 0, NULL, NULL}
2362 ot->name = "Set Plane";
2363 ot->description = "Set plane based on 3 selected bundles by moving camera (or it's parent if present) in 3D space";
2364 ot->idname = "CLIP_OT_set_plane";
2367 ot->exec = set_plane_exec;
2368 ot->poll = set_orientation_poll;
2371 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2374 RNA_def_enum(ot->srna, "plane", plane_items, 0, "Plane", "Plane to be used for orientation");
2377 /********************** set axis operator *********************/
2379 static int set_axis_exec(bContext *C, wmOperator *op)
2381 SpaceClip *sc = CTX_wm_space_clip(C);
2382 MovieClip *clip = ED_space_clip_get_clip(sc);
2383 MovieTracking *tracking = &clip->tracking;
2384 MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(tracking);
2385 MovieTrackingTrack *track;
2386 Scene *scene = CTX_data_scene(C);
2388 ListBase *tracksbase;
2389 int axis = RNA_enum_get(op->ptr, "axis");
2391 if (count_selected_bundles(C) != 1) {
2392 BKE_report(op->reports, RPT_ERROR, "Single track with bundle should be selected to define axis");
2394 return OPERATOR_CANCELLED;
2397 object = get_orientation_object(C);
2399 BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
2401 return OPERATOR_CANCELLED;
2404 tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object);
2406 track = tracksbase->first;
2408 if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_HAS_BUNDLE))
2411 track = track->next;
2414 set_axis(scene, object, clip, tracking_object, track, axis == 0 ? 'X' : 'Y');
2416 DAG_id_tag_update(&clip->id, 0);
2417 DAG_id_tag_update(&object->id, OB_RECALC_OB);
2419 WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
2420 WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
2422 return OPERATOR_FINISHED;
2425 void CLIP_OT_set_axis(wmOperatorType *ot)
2427 static EnumPropertyItem axis_actions[] = {
2428 {0, "X", 0, "X", "Align bundle align X axis"},
2429 {1, "Y", 0, "Y", "Align bundle align Y axis"},
2430 {0, NULL, 0, NULL, NULL}
2434 ot->name = "Set Axis";
2435 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";
2436 ot->idname = "CLIP_OT_set_axis";
2439 ot->exec = set_axis_exec;
2440 ot->poll = set_orientation_poll;
2443 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2446 RNA_def_enum(ot->srna, "axis", axis_actions, 0, "Axis", "Axis to use to align bundle along");
2449 /********************** set scale operator *********************/
2451 static int do_set_scale(bContext *C, wmOperator *op, bool scale_solution, bool apply_scale)
2453 SpaceClip *sc = CTX_wm_space_clip(C);
2454 MovieClip *clip = ED_space_clip_get_clip(sc);
2455 MovieTracking *tracking = &clip->tracking;
2456 MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(tracking);
2457 MovieTrackingTrack *track;
2458 Scene *scene = CTX_data_scene(C);
2459 Object *object = NULL;
2460 Object *camera = get_camera_with_movieclip(scene, clip);
2461 ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
2463 float vec[2][3], mat[4][4], scale;
2464 float dist = RNA_float_get(op->ptr, "distance");
2466 if (count_selected_bundles(C) != 2) {
2467 BKE_report(op->reports, RPT_ERROR, "Two tracks with bundles should be selected to set scale");
2469 return OPERATOR_CANCELLED;
2472 if (!scale_solution && !apply_scale) {
2473 object = get_orientation_object(C);
2475 BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
2477 return OPERATOR_CANCELLED;
2481 BKE_tracking_get_camera_object_matrix(scene, camera, mat);
2483 track = tracksbase->first;
2485 if (TRACK_VIEW_SELECTED(sc, track)) {
2486 mul_v3_m4v3(vec[tot], mat, track->bundle_pos);
2490 track = track->next;
2493 sub_v3_v3(vec[0], vec[1]);
2495 if (len_v3(vec[0]) > 1e-5f) {
2496 scale = dist / len_v3(vec[0]);
2499 /* Apply scale on reconstructed scene itself */
2500 MovieTrackingReconstruction *reconstruction = BKE_tracking_get_active_reconstruction(tracking);
2501 MovieReconstructedCamera *reconstructed_cameras;
2504 for (track = tracksbase->first; track; track = track->next) {
2505 mul_v3_fl(track->bundle_pos, scale);
2508 reconstructed_cameras = reconstruction->cameras;
2509 for (i = 0; i < reconstruction->camnr; i++) {
2510 mul_v3_fl(reconstructed_cameras[i].mat[3], scale);
2513 WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
2514 WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
2517 if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
2518 mul_v3_fl(object->size, scale);
2519 mul_v3_fl(object->loc, scale);
2521 else if (!scale_solution) {
2522 Object *solver_camera = object_solver_camera(scene, object);
2524 object->size[0] = object->size[1] = object->size[2] = 1.0f / scale;
2526 if (solver_camera) {
2527 object->size[0] /= solver_camera->size[0];
2528 object->size[1] /= solver_camera->size[1];
2529 object->size[2] /= solver_camera->size[2];
2533 tracking_object->scale = scale;
2536 DAG_id_tag_update(&clip->id, 0);
2539 DAG_id_tag_update(&object->id, OB_RECALC_OB);
2541 WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
2542 WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
2546 return OPERATOR_FINISHED;
2549 static int set_scale_exec(bContext *C, wmOperator *op)
2551 return do_set_scale(C, op, false, false);
2554 static int set_scale_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
2556 SpaceClip *sc = CTX_wm_space_clip(C);
2557 MovieClip *clip = ED_space_clip_get_clip(sc);
2559 if (!RNA_struct_property_is_set(op->ptr, "distance"))
2560 RNA_float_set(op->ptr, "distance", clip->tracking.settings.dist);
2562 return set_scale_exec(C, op);
2565 void CLIP_OT_set_scale(wmOperatorType *ot)
2568 ot->name = "Set Scale";
2569 ot->description = "Set scale of scene by scaling camera (or it's parent if present)";
2570 ot->idname = "CLIP_OT_set_scale";
2573 ot->exec = set_scale_exec;
2574 ot->invoke = set_scale_invoke;
2575 ot->poll = set_orientation_poll;
2578 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2581 RNA_def_float(ot->srna, "distance", 0.0f, -FLT_MAX, FLT_MAX,
2582 "Distance", "Distance between selected tracks", -100.0f, 100.0f);
2585 /********************** set solution scale operator *********************/
2587 static int set_solution_scale_poll(bContext *C)
2589 SpaceClip *sc = CTX_wm_space_clip(C);
2592 MovieClip *clip = ED_space_clip_get_clip(sc);
2595 MovieTracking *tracking = &clip->tracking;
2596 MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(tracking);
2598 return (tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0;
2605 static int set_solution_scale_exec(bContext *C, wmOperator *op)
2607 return do_set_scale(C, op, true, false);
2610 static int set_solution_scale_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
2612 SpaceClip *sc = CTX_wm_space_clip(C);
2613 MovieClip *clip = ED_space_clip_get_clip(sc);
2615 if (!RNA_struct_property_is_set(op->ptr, "distance"))
2616 RNA_float_set(op->ptr, "distance", clip->tracking.settings.object_distance);
2618 return set_solution_scale_exec(C, op);
2621 void CLIP_OT_set_solution_scale(wmOperatorType *ot)
2624 ot->name = "Set Solution Scale";
2625 ot->description = "Set object solution scale using distance between two selected tracks";
2626 ot->idname = "CLIP_OT_set_solution_scale";
2629 ot->exec = set_solution_scale_exec;
2630 ot->invoke = set_solution_scale_invoke;
2631 ot->poll = set_solution_scale_poll;
2634 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2637 RNA_def_float(ot->srna, "distance", 0.0f, -FLT_MAX, FLT_MAX,
2638 "Distance", "Distance between selected tracks", -100.0f, 100.0f);
2641 /********************** apply solution scale operator *********************/
2643 static int apply_solution_scale_poll(bContext *C)
2645 SpaceClip *sc = CTX_wm_space_clip(C);
2648 MovieClip *clip = ED_space_clip_get_clip(sc);
2651 MovieTracking *tracking = &clip->tracking;
2652 MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(tracking);
2654 return tracking_object->flag & TRACKING_OBJECT_CAMERA;
2661 static int apply_solution_scale_exec(bContext *C, wmOperator *op)
2663 return do_set_scale(C, op, false, true);
2666 static int apply_solution_scale_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
2668 SpaceClip *sc = CTX_wm_space_clip(C);
2669 MovieClip *clip = ED_space_clip_get_clip(sc);
2671 if (!RNA_struct_property_is_set(op->ptr, "distance"))
2672 RNA_float_set(op->ptr, "distance", clip->tracking.settings.dist);
2674 return apply_solution_scale_exec(C, op);
2677 void CLIP_OT_apply_solution_scale(wmOperatorType *ot)
2680 ot->name = "Apply Solution Scale";
2681 ot->description = "Apply scale on solution itself to make distance between selected tracks equals to desired";
2682 ot->idname = "CLIP_OT_apply_solution_scale";
2685 ot->exec = apply_solution_scale_exec;
2686 ot->invoke = apply_solution_scale_invoke;
2687 ot->poll = apply_solution_scale_poll;
2690 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2693 RNA_def_float(ot->srna, "distance", 0.0f, -FLT_MAX, FLT_MAX,
2694 "Distance", "Distance between selected tracks", -100.0f, 100.0f);
2697 /********************** set principal center operator *********************/
2699 static int set_center_principal_exec(bContext *C, wmOperator *UNUSED(op))
2701 SpaceClip *sc = CTX_wm_space_clip(C);
2702 MovieClip *clip = ED_space_clip_get_clip(sc);
2705 BKE_movieclip_get_size(clip, &sc->user, &width, &height);
2707 if (width == 0 || height == 0)
2708 return OPERATOR_CANCELLED;
2710 clip->tracking.camera.principal[0] = ((float)width) / 2.0f;
2711 clip->tracking.camera.principal[1] = ((float)height) / 2.0f;
2713 WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip);
2715 return OPERATOR_FINISHED;
2718 void CLIP_OT_set_center_principal(wmOperatorType *ot)
2721 ot->name = "Set Principal to Center";
2722 ot->description = "Set optical center to center of footage";
2723 ot->idname = "CLIP_OT_set_center_principal";
2726 ot->exec = set_center_principal_exec;
2727 ot->poll = ED_space_clip_tracking_poll;
2730 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2733 /********************** hide tracks operator *********************/
2735 static int hide_tracks_exec(bContext *C, wmOperator *op)
2737 SpaceClip *sc = CTX_wm_space_clip(C);
2738 MovieClip *clip = ED_space_clip_get_clip(sc);
2739 MovieTrackingTrack *track;
2740 MovieTracking *tracking = &clip->tracking;
2741 ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
2742 MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking);
2745 unselected = RNA_boolean_get(op->ptr, "unselected");
2747 track = tracksbase->first;
2749 if (unselected == 0 && TRACK_VIEW_SELECTED(sc, track)) {
2750 track->flag |= TRACK_HIDDEN;
2752 else if (unselected == 1 && !TRACK_VIEW_SELECTED(sc, track)) {
2753 track->flag |= TRACK_HIDDEN;
2756 track = track->next;
2759 if (act_track && act_track->flag & TRACK_HIDDEN)
2760 clip->tracking.act_track = NULL;
2762 if (unselected == 0) {
2763 /* no selection on screen now, unlock view so it can be scrolled nice again */
2764 sc->flag &= ~SC_LOCK_SELECTION;
2767 BKE_tracking_dopesheet_tag_update(tracking);
2769 WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, NULL);
2771 return OPERATOR_FINISHED;
2774 void CLIP_OT_hide_tracks(wmOperatorType *ot)
2777 ot->name = "Hide Tracks";
2778 ot->description = "Hide selected tracks";
2779 ot->idname = "CLIP_OT_hide_tracks";
2782 ot->exec = hide_tracks_exec;
2783 ot->poll = ED_space_clip_tracking_poll;
2786 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2789 RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected tracks");
2792 /********************** hide tracks clear operator *********************/
2794 static int hide_tracks_clear_exec(bContext *C, wmOperator *UNUSED(op))
2796 SpaceClip *sc = CTX_wm_space_clip(C);
2797 MovieClip *clip = ED_space_clip_get_clip(sc);
2798 MovieTracking *tracking = &clip->tracking;
2799 ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
2800 MovieTrackingTrack *track;
2802 track = tracksbase->first;
2804 track->flag &= ~TRACK_HIDDEN;
2806 track = track->next;
2809 BKE_tracking_dopesheet_tag_update(tracking);
2811 WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, NULL);
2813 return OPERATOR_FINISHED;
2816 void CLIP_OT_hide_tracks_clear(wmOperatorType *ot)
2819 ot->name = "Hide Tracks Clear";
2820 ot->description = "Clear hide selected tracks";
2821 ot->idname = "CLIP_OT_hide_tracks_clear";
2824 ot->exec = hide_tracks_clear_exec;
2825 ot->poll = ED_space_clip_tracking_poll;
2828 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2831 /********************** detect features operator *********************/
2833 static bGPDlayer *detect_get_layer(MovieClip *clip)
2840 layer = clip->gpd->layers.first;
2842 if (layer->flag & GP_LAYER_ACTIVE)
2845 layer = layer->next;
2851 static int detect_features_exec(bContext *C, wmOperator *op)
2853 SpaceClip *sc = CTX_wm_space_clip(C);
2854 MovieClip *clip = ED_space_clip_get_clip(sc);
2855 int clip_flag = clip->flag & MCLIP_TIMECODE_FLAGS;
2856 ImBuf *ibuf = BKE_movieclip_get_ibuf_flag(clip, &sc->user, clip_flag, MOVIECLIP_CACHE_SKIP);
2857 MovieTracking *tracking = &clip->tracking;
2858 ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
2859 MovieTrackingTrack *track = tracksbase->first;
2860 int placement = RNA_enum_get(op->ptr, "placement");
2861 int margin = RNA_int_get(op->ptr, "margin");
2862 int min_trackability = RNA_int_get(op->ptr, "min_trackability");
2863 int min_distance = RNA_int_get(op->ptr, "min_distance");
2864 int place_outside_layer = 0;
2865 int framenr = ED_space_clip_get_clip_frame_number(sc);
2866 bGPDlayer *layer = NULL;
2869 BKE_report(op->reports, RPT_ERROR, "Feature detection requires valid clip frame");
2870 return OPERATOR_CANCELLED;
2873 if (placement != 0) {
2874 layer = detect_get_layer(clip);
2875 place_outside_layer = placement == 2;
2878 /* deselect existing tracks */
2880 track->flag &= ~SELECT;
2881 track->pat_flag &= ~SELECT;
2882 track->search_flag &= ~SELECT;
2884 track = track->next;
2887 BKE_tracking_detect_fast(tracking, tracksbase, ibuf, framenr, margin,
2888 min_trackability, min_distance, layer, place_outside_layer);
2890 IMB_freeImBuf(ibuf);
2892 BKE_tracking_dopesheet_tag_update(tracking);
2893 WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, NULL);
2895 return OPERATOR_FINISHED;
2898 void CLIP_OT_detect_features(wmOperatorType *ot)
2900 static EnumPropertyItem placement_items[] = {
2901 {0, "FRAME", 0, "Whole Frame", "Place markers across the whole frame"},
2902 {1, "INSIDE_GPENCIL", 0, "Inside grease pencil", "Place markers only inside areas outlined with grease pencil"},
2903 {2, "OUTSIDE_GPENCIL", 0, "Outside grease pencil", "Place markers only outside areas outlined with grease pencil"},
2904 {0, NULL, 0, NULL, NULL}
2908 ot->name = "Detect Features";
2909 ot->description = "Automatically detect features and place markers to track";
2910 ot->idname = "CLIP_OT_detect_features";
2913 ot->exec = detect_features_exec;
2914 ot->poll = ED_space_clip_tracking_poll;
2917 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2920 RNA_def_enum(ot->srna, "placement", placement_items, 0, "Placement", "Placement for detected features");
2921 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);
2922 RNA_def_int(ot->srna, "min_trackability", 16, 0, INT_MAX, "Trackability", "Minimum trackability score to add a corner", 0, 300);
2923 RNA_def_int(ot->srna, "min_distance", 120, 0, INT_MAX, "Distance", "Minimal distance accepted between two corners", 0, 300);
2926 /********************** frame jump operator *********************/
2928 static int frame_jump_exec(bContext *C, wmOperator *op)
2930 Scene *scene = CTX_data_scene(C);
2931 SpaceClip *sc = CTX_wm_space_clip(C);
2932 MovieClip *clip = ED_space_clip_get_clip(sc);
2933 MovieTrackingTrack *track;
2934 int pos = RNA_enum_get(op->ptr, "position");
2937 if (pos <= 1) { /* jump to path */
2938 track = BKE_tracking_track_get_active(&clip->tracking);
2941 return OPERATOR_CANCELLED;
2943 delta = pos == 1 ? 1 : -1;
2945 while (sc->user.framenr + delta >= SFRA && sc->user.framenr + delta <= EFRA) {
2946 int framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, sc->user.framenr + delta);
2947 MovieTrackingMarker *marker = BKE_tracking_marker_get_exact(track, framenr);
2949 if (!marker || marker->flag & MARKER_DISABLED)
2952 sc->user.framenr += delta;
2955 else { /* to to failed frame */
2956 if (clip->tracking.reconstruction.flag & TRACKING_RECONSTRUCTED) {
2957 int a = ED_space_clip_get_clip_frame_number(sc);
2958 MovieTracking *tracking = &clip->tracking;
2959 MovieTrackingObject *object = BKE_tracking_object_get_active(tracking);
2961 delta = pos == 3 ? 1 : -1;
2965 while (a + delta >= SFRA && a + delta <= EFRA) {
2966 MovieReconstructedCamera *cam;
2968 cam = BKE_tracking_camera_get_reconstructed(tracking, object, a);
2971 sc->user.framenr = BKE_movieclip_remap_clip_to_scene_frame(clip, a);
2981 if (CFRA != sc->user.framenr) {
2982 CFRA = sc->user.framenr;
2983 sound_seek_scene(CTX_data_main(C), CTX_data_scene(C));
2985 WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
2988 WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, NULL);
2990 return OPERATOR_FINISHED;
2993 void CLIP_OT_frame_jump(wmOperatorType *ot)
2995 static EnumPropertyItem position_items[] = {
2996 {0, "PATHSTART", 0, "Path Start", "Jump to start of current path"},
2997 {1, "PATHEND", 0, "Path End", "Jump to end of current path"},
2998 {2, "FAILEDPREV", 0, "Previous Failed", "Jump to previous failed frame"},
2999 {2, "FAILNEXT", 0, "Next Failed", "Jump to next failed frame"},
3000 {0, NULL, 0, NULL, NULL}
3004 ot->name = "Jump to Frame";
3005 ot->description = "Jump to special frame";
3006 ot->idname = "CLIP_OT_frame_jump";
3009 ot->exec = frame_jump_exec;
3010 ot->poll = ED_space_clip_poll;
3013 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3016 RNA_def_enum(ot->srna, "position", position_items, 0, "Position", "Position to jump to");
3019 /********************** join tracks operator *********************/
3021 static int join_tracks_exec(bContext *C, wmOperator *op)
3023 SpaceClip *sc = CTX_wm_space_clip(C);
3024 MovieClip *clip = ED_space_clip_get_clip(sc);
3025 MovieTracking *tracking = &clip->tracking;
3026 ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
3027 MovieTrackingTrack *act_track, *track, *next;
3029 act_track = BKE_tracking_track_get_active(tracking);
3032 BKE_report(op->reports, RPT_ERROR, "No active track to join to");
3033 return OPERATOR_CANCELLED;
3036 track = tracksbase->first;
3040 if (TRACK_VIEW_SELECTED(sc, track) && track != act_track) {
3041 BKE_tracking_tracks_join(tracking, act_track, track);
3043 if (tracking->stabilization.rot_track == track)
3044 tracking->stabilization.rot_track = act_track;
3046 BKE_tracking_track_free(track);
3047 BLI_freelinkN(tracksbase, track);
3053 WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip);
3055 return OPERATOR_FINISHED;
3058 void CLIP_OT_join_tracks(wmOperatorType *ot)
3061 ot->name = "Join Tracks";
3062 ot->description = "Join selected tracks";
3063 ot->idname = "CLIP_OT_join_tracks";
3066 ot->exec = join_tracks_exec;
3067 ot->poll = ED_space_clip_tracking_poll;
3070 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3073 /********************** lock tracks operator *********************/
3075 static int lock_tracks_exec(bContext *C, wmOperator *op)
3077 SpaceClip *sc = CTX_wm_space_clip(C);
3078 MovieClip *clip = ED_space_clip_get_clip(sc);
3079 MovieTracking *tracking = &clip->tracking;
3080 ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
3081 MovieTrackingTrack *track = tracksbase->first;
3082 int action = RNA_enum_get(op->ptr, "action");
3085 if (TRACK_VIEW_SELECTED(sc, track)) {
3087 track->flag |= TRACK_LOCKED;
3088 else if (action == 1)
3089 track->flag &= ~TRACK_LOCKED;
3090 else track->flag ^= TRACK_LOCKED;
3093 track = track->next;
3096 WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
3098 return OPERATOR_FINISHED;
3101 void CLIP_OT_lock_tracks(wmOperatorType *ot)
3103 static EnumPropertyItem actions_items[] = {
3104 {0, "LOCK", 0, "Lock", "Lock selected tracks"},
3105 {1, "UNLOCK", 0, "Unlock", "Unlock selected tracks"},
3106 {2, "TOGGLE", 0, "Toggle", "Toggle locked flag for selected tracks"},
3107 {0, NULL, 0, NULL, NULL}
3111 ot->name = "Lock Tracks";
3112 ot->description = "Lock/unlock selected tracks";
3113 ot->idname = "CLIP_OT_lock_tracks";
3116 ot->exec = lock_tracks_exec;
3117 ot->poll = ED_space_clip_tracking_poll;
3120 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3123 RNA_def_enum(ot->srna, "action", actions_items, 0, "Action", "Lock action to execute");
3126 /********************** set keyframe operator *********************/
3128 static int set_solver_keyframe_exec(bContext *C, wmOperator *op)
3130 SpaceClip *sc = CTX_wm_space_clip(C);
3131 MovieClip *clip = ED_space_clip_get_clip(sc);
3132 MovieTracking *tracking = &clip->tracking;
3133 MovieTrackingObject *object = BKE_tracking_object_get_active(tracking);
3134 int keyframe = RNA_enum_get(op->ptr, "keyframe");
3135 int framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, sc->user.framenr);
3138 object->keyframe1 = framenr;
3140 object->keyframe2 = framenr;
3142 WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip);
3144 return OPERATOR_FINISHED;
3147 void CLIP_OT_set_solver_keyframe(wmOperatorType *ot)
3149 static EnumPropertyItem keyframe_items[] = {
3150 {0, "KEYFRAME_A", 0, "Keyframe A", ""},
3151 {1, "KEYFRAME_B", 0, "Keyframe B", ""},
3152 {0, NULL, 0, NULL, NULL}
3156 ot->name = "Set Solver Keyframe";
3157 ot->description = "Set keyframe used by solver";
3158 ot->idname = "CLIP_OT_set_solver_keyframe";
3161 ot->exec = set_solver_keyframe_exec;
3162 ot->poll = ED_space_clip_tracking_poll;
3165 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3168 RNA_def_enum(ot->srna, "keyframe", keyframe_items, 0, "Keyframe", "Keyframe to set");
3171 /********************** track copy color operator *********************/
3173 static int track_copy_color_exec(bContext *C, wmOperator *UNUSED(op))
3175 SpaceClip *sc = CTX_wm_space_clip(C);
3176 MovieClip *clip = ED_space_clip_get_clip(sc);
3177 MovieTracking *tracking = &clip->tracking;
3178 ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
3179 MovieTrackingTrack *track, *act_track = BKE_tracking_track_get_active(tracking);
3182 return OPERATOR_CANCELLED;
3184 track = tracksbase->first;
3186 if (TRACK_VIEW_SELECTED(sc, track) && track != act_track) {
3187 track->flag &= ~TRACK_CUSTOMCOLOR;
3189 if (act_track->flag & TRACK_CUSTOMCOLOR) {
3190 copy_v3_v3(track->color, act_track->color);
3191 track->flag |= TRACK_CUSTOMCOLOR;
3195 track = track->next;
3198 WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip);
3200 return OPERATOR_FINISHED;
3203 void CLIP_OT_track_copy_color(wmOperatorType *ot)
3206 ot->name = "Copy Color";
3207 ot->description = "Copy color to all selected tracks";
3208 ot->idname = "CLIP_OT_track_copy_color";
3211 ot->exec = track_copy_color_exec;
3212 ot->poll = ED_space_clip_tracking_poll;
3215 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3218 /********************** add 2d stabilization tracks operator *********************/
3220 static int stabilize_2d_poll(bContext *C)
3222 if (ED_space_clip_tracking_poll(C)) {
3223 SpaceClip *sc = CTX_wm_space_clip(C);
3224 MovieClip *clip = ED_space_clip_get_clip(sc);
3225 MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(&clip->tracking);
3227 return tracking_object->flag & TRACKING_OBJECT_CAMERA;
3233 static int stabilize_2d_add_exec(bContext *C, wmOperator *UNUSED(op))
3235 SpaceClip *sc = CTX_wm_space_clip(C);
3236 MovieClip *clip = ED_space_clip_get_clip(sc);
3237 MovieTracking *tracking = &clip->tracking;
3238 ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
3239 MovieTrackingTrack *track;
3240 MovieTrackingStabilization *stab = &tracking->stabilization;
3243 track = tracksbase->first;
3245 if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_USE_2D_STAB) == 0) {
3246 track->flag |= TRACK_USE_2D_STAB;
3252 track = track->next;