/* draw grease pencil */ void clip_draw_grease_pencil(bContext *C, int onlyv2d) { SpaceClip *sc = CTX_wm_space_clip(C); MovieClip *clip = ED_space_clip_get_clip(sc); if (!clip) return; if (onlyv2d) { /* if manual calibration is used then grease pencil data is already * drawn in draw_distortion */ if ((sc->flag & SC_MANUAL_CALIBRATION) == 0) { glPushMatrix(); glMultMatrixf(sc->unistabmat); if (sc->gpencil_src == SC_GPENCIL_SRC_TRACK) { MovieTrackingTrack *track = BKE_tracking_track_get_active(&sc->clip->tracking); if (track) { int framenr = ED_space_clip_get_clip_frame_number(sc); MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr); glTranslatef(marker->pos[0], marker->pos[1], 0.0f); } } draw_gpencil_2dimage(C); glPopMatrix(); } } else { draw_gpencil_view2d(C, 0); } }
static int graph_disable_markers_exec(bContext *C, wmOperator *op) { SpaceClip *sc = CTX_wm_space_clip(C); MovieClip *clip = ED_space_clip_get_clip(sc); MovieTracking *tracking = &clip->tracking; MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking); MovieTrackingMarker *marker; int action = RNA_enum_get(op->ptr, "action"); int a; if (!act_track || (act_track->flag & TRACK_LOCKED)) return OPERATOR_CANCELLED; for (a = 0; a < act_track->markersnr; a++) { marker = &act_track->markers[a]; if (marker->flag & MARKER_GRAPH_SEL) { if (action == 0) marker->flag |= MARKER_DISABLED; else if (action == 1) marker->flag &= ~MARKER_DISABLED; else marker->flag ^= MARKER_DISABLED; } } DAG_id_tag_update(&clip->id, 0); WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip); return OPERATOR_FINISHED; }
static int border_select_graph_exec(bContext *C, wmOperator *op) { SpaceClip *sc = CTX_wm_space_clip(C); ARegion *ar = CTX_wm_region(C); MovieClip *clip = ED_space_clip_get_clip(sc); MovieTracking *tracking = &clip->tracking; MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking); BorderSelectuserData userdata; rctf rect; if (act_track == NULL) { return OPERATOR_CANCELLED; } /* get rectangle from operator */ WM_operator_properties_border_to_rctf(op, &rect); UI_view2d_region_to_view_rctf(&ar->v2d, &rect, &userdata.rect); userdata.changed = false; userdata.mode = RNA_int_get(op->ptr, "gesture_mode"); userdata.extend = RNA_boolean_get(op->ptr, "extend"); clip_graph_tracking_values_iterate_track(sc, act_track, &userdata, border_select_cb, NULL, NULL); if (userdata.changed) { WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL); return OPERATOR_FINISHED; } return OPERATOR_CANCELLED; }
static void draw_tracks_error_curves(SpaceClip *sc) { MovieClip *clip = ED_space_clip_get_clip(sc); MovieTracking *tracking = &clip->tracking; TrackErrorCurveUserData data; data.clip = clip; data.tracking = tracking; data.tracking_object = BKE_tracking_object_get_active(tracking); data.active_track = BKE_tracking_track_get_active(tracking); data.matrix_initialized = false; BKE_movieclip_get_size(clip, &sc->user, &data.width, &data.height); data.aspy = 1.0f / tracking->camera.pixel_aspect; if (!data.width || !data.height) { return; } clip_graph_tracking_values_iterate(sc, (sc->flag & SC_SHOW_GRAPH_SEL_ONLY) != 0, (sc->flag & SC_SHOW_GRAPH_HIDDEN) != 0, &data, tracking_error_segment_point_cb, tracking_error_segment_start_cb, tracking_error_segment_end_cb); }
static bool mouse_select_knot(bContext *C, float co[2], bool extend) { SpaceClip *sc = CTX_wm_space_clip(C); MovieClip *clip = ED_space_clip_get_clip(sc); ARegion *ar = CTX_wm_region(C); View2D *v2d = &ar->v2d; MovieTracking *tracking = &clip->tracking; MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking); static const int delta = 6; if (act_track) { MouseSelectUserData userdata; mouse_select_init_data(&userdata, co); clip_graph_tracking_values_iterate_track(sc, act_track, &userdata, find_nearest_tracking_knot_cb, NULL, NULL); if (userdata.marker) { int x1, y1, x2, y2; if (UI_view2d_view_to_region_clip(v2d, co[0], co[1], &x1, &y1) && UI_view2d_view_to_region_clip(v2d, userdata.min_co[0], userdata.min_co[1], &x2, &y2) && (abs(x2 - x1) <= delta && abs(y2 - y1) <= delta)) { if (!extend) { SelectUserData selectdata = {SEL_DESELECT}; clip_graph_tracking_iterate(sc, (sc->flag & SC_SHOW_GRAPH_SEL_ONLY) != 0, (sc->flag & SC_SHOW_GRAPH_HIDDEN) != 0, &selectdata, toggle_selection_cb); } if (userdata.coord == 0) { if (extend && (userdata.marker->flag & MARKER_GRAPH_SEL_X) != 0) userdata.marker->flag &= ~MARKER_GRAPH_SEL_X; else userdata.marker->flag |= MARKER_GRAPH_SEL_X; } else { if (extend && (userdata.marker->flag & MARKER_GRAPH_SEL_Y) != 0) userdata.marker->flag &= ~MARKER_GRAPH_SEL_Y; else userdata.marker->flag |= MARKER_GRAPH_SEL_Y; } return true; } } } return false; }
static int delete_curve_exec(bContext *C, wmOperator *UNUSED(op)) { SpaceClip *sc = CTX_wm_space_clip(C); MovieClip *clip = ED_space_clip_get_clip(sc); MovieTracking *tracking = &clip->tracking; MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking); if (!act_track) return OPERATOR_CANCELLED; clip_delete_track(C, clip, act_track); return OPERATOR_FINISHED; }
static int graph_select_all_markers_exec(bContext *C, wmOperator *op) { SpaceClip *sc = CTX_wm_space_clip(C); MovieClip *clip = ED_space_clip_get_clip(sc); MovieTracking *tracking = &clip->tracking; MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking); MovieTrackingMarker *marker; int action = RNA_enum_get(op->ptr, "action"); int a; if (!act_track) return OPERATOR_CANCELLED; if (action == SEL_TOGGLE) { action = SEL_SELECT; for (a = 0; a < act_track->markersnr; a++) { marker = &act_track->markers[a]; if (marker->flag & MARKER_GRAPH_SEL) { action = SEL_DESELECT; break; } } } for (a = 0; a < act_track->markersnr; a++) { marker = &act_track->markers[a]; switch (action) { case SEL_SELECT: marker->flag |= MARKER_GRAPH_SEL; break; case SEL_DESELECT: marker->flag &= ~MARKER_GRAPH_SEL; break; case SEL_INVERT: marker->flag ^= MARKER_GRAPH_SEL; break; } } WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL); return OPERATOR_FINISHED; }
void clip_delete_track(bContext *C, MovieClip *clip, MovieTrackingTrack *track) { MovieTracking *tracking = &clip->tracking; MovieTrackingStabilization *stab = &tracking->stabilization; MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking); ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking); bool has_bundle = false, update_stab = false; char track_name_escaped[MAX_NAME], prefix[MAX_NAME * 2]; if (track == act_track) tracking->act_track = NULL; if (track == stab->rot_track) { stab->rot_track = NULL; update_stab = true; } /* handle reconstruction display in 3d viewport */ if (track->flag & TRACK_HAS_BUNDLE) has_bundle = true; /* Make sure no plane will use freed track */ BKE_tracking_plane_tracks_remove_point_track(tracking, track); /* Delete f-curves associated with the track (such as weight, i.e.) */ BLI_strescape(track_name_escaped, track->name, sizeof(track_name_escaped)); BLI_snprintf(prefix, sizeof(prefix), "tracks[\"%s\"]", track_name_escaped); BKE_animdata_fix_paths_remove(&clip->id, prefix); BKE_tracking_track_free(track); BLI_freelinkN(tracksbase, track); WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip); if (update_stab) { tracking->stabilization.ok = false; WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip); } DAG_id_tag_update(&clip->id, 0); if (has_bundle) WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL); }
static bool mouse_select_curve(bContext *C, float co[2], bool extend) { SpaceClip *sc = CTX_wm_space_clip(C); MovieClip *clip = ED_space_clip_get_clip(sc); MovieTracking *tracking = &clip->tracking; MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking); MouseSelectUserData userdata; mouse_select_init_data(&userdata, co); clip_graph_tracking_values_iterate(sc, (sc->flag & SC_SHOW_GRAPH_SEL_ONLY) != 0, (sc->flag & SC_SHOW_GRAPH_HIDDEN) != 0, &userdata, find_nearest_tracking_segment_cb, NULL, find_nearest_tracking_segment_end_cb); if (userdata.track) { if (extend) { if (act_track == userdata.track) { /* currently only single curve can be selected (selected curve represents active track) */ act_track = NULL; } } else if (act_track != userdata.track) { SelectUserData selectdata = {SEL_DESELECT}; MovieTrackingObject *object = BKE_tracking_object_get_active(tracking); tracking->act_track = userdata.track; if ((sc->flag & SC_SHOW_GRAPH_SEL_ONLY) == 0) { ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object); BKE_tracking_track_select(tracksbase, userdata.track, TRACK_AREA_ALL, false); } /* deselect all knots on newly selected curve */ clip_graph_tracking_iterate(sc, (sc->flag & SC_SHOW_GRAPH_SEL_ONLY) != 0, (sc->flag & SC_SHOW_GRAPH_HIDDEN) != 0, &selectdata, toggle_selection_cb); } return true; } return false; }
static int mouse_select(bContext *C, float co[2], int extend) { SpaceClip *sc = CTX_wm_space_clip(C); MovieClip *clip = ED_space_clip_get_clip(sc); MovieTracking *tracking = &clip->tracking; ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking); MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking); MovieTrackingTrack *track = NULL; /* selected marker */ track = find_nearest_track(sc, tracksbase, co); if (track) { int area = track_mouse_area(C, co, track); if (!extend || !TRACK_VIEW_SELECTED(sc, track)) area = TRACK_AREA_ALL; if (extend && TRACK_AREA_SELECTED(track, area)) { if (track == act_track) BKE_tracking_track_deselect(track, area); else clip->tracking.act_track = track; } else { if (area == TRACK_AREA_POINT) area = TRACK_AREA_ALL; BKE_tracking_track_select(tracksbase, track, area, extend); clip->tracking.act_track = track; } } if (!extend) { sc->xlockof = 0.0f; sc->ylockof = 0.0f; } BKE_tracking_dopesheet_tag_update(tracking); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL); return OPERATOR_FINISHED; }
static int delete_knot_exec(bContext *C, wmOperator *UNUSED(op)) { SpaceClip *sc = CTX_wm_space_clip(C); MovieClip *clip = ED_space_clip_get_clip(sc); MovieTracking *tracking = &clip->tracking; MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking); if (act_track) { int a = 0; while (a < act_track->markersnr) { MovieTrackingMarker *marker = &act_track->markers[a]; if (marker->flag & MARKER_GRAPH_SEL) clip_delete_marker(C, clip, act_track, marker); else a++; } } return OPERATOR_FINISHED; }
static void draw_tracks_motion_curves(View2D *v2d, SpaceClip *sc) { MovieClip *clip = ED_space_clip_get_clip(sc); MovieTracking *tracking = &clip->tracking; MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking); int width, height; TrackMotionCurveUserData userdata; BKE_movieclip_get_size(clip, &sc->user, &width, &height); if (!width || !height) return; /* non-selected knot handles */ userdata.hsize = UI_GetThemeValuef(TH_HANDLE_VERTEX_SIZE); userdata.sel = false; userdata.act_track = act_track; UI_view2d_scale_get(v2d, &userdata.xscale, &userdata.yscale); clip_graph_tracking_values_iterate(sc, (sc->flag & SC_SHOW_GRAPH_SEL_ONLY) != 0, (sc->flag & SC_SHOW_GRAPH_HIDDEN) != 0, &userdata, tracking_segment_knot_cb, NULL, NULL); /* draw graph lines */ glEnable(GL_BLEND); clip_graph_tracking_values_iterate(sc, (sc->flag & SC_SHOW_GRAPH_SEL_ONLY) != 0, (sc->flag & SC_SHOW_GRAPH_HIDDEN) != 0, act_track, tracking_segment_point_cb, tracking_segment_start_cb, tracking_segment_end_cb); glDisable(GL_BLEND); /* selected knot handles on top of curves */ userdata.sel = true; clip_graph_tracking_values_iterate(sc, (sc->flag & SC_SHOW_GRAPH_SEL_ONLY) != 0, (sc->flag & SC_SHOW_GRAPH_HIDDEN) != 0, &userdata, tracking_segment_knot_cb, NULL, NULL); }
static void draw_movieclip_cache(SpaceClip *sc, ARegion *ar, MovieClip *clip, Scene *scene) { float x; int *points, totseg, i, a; float sfra = SFRA, efra = EFRA, framelen = ar->winx / (efra - sfra + 1); MovieTracking *tracking = &clip->tracking; MovieTrackingObject *act_object = BKE_tracking_object_get_active(tracking); MovieTrackingTrack *act_track = BKE_tracking_track_get_active(&clip->tracking); MovieTrackingPlaneTrack *act_plane_track = BKE_tracking_plane_track_get_active(&clip->tracking); MovieTrackingReconstruction *reconstruction = BKE_tracking_get_active_reconstruction(tracking); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); /* cache background */ ED_region_cache_draw_background(ar); /* cached segments -- could be usefu lto debug caching strategies */ BKE_movieclip_get_cache_segments(clip, &sc->user, &totseg, &points); ED_region_cache_draw_cached_segments(ar, totseg, points, sfra, efra); /* track */ if (act_track || act_plane_track) { for (i = sfra - clip->start_frame + 1, a = 0; i <= efra - clip->start_frame + 1; i++) { int framenr; int markersnr = generic_track_get_markersnr(act_track, act_plane_track); while (a < markersnr) { int marker_framenr = generic_track_get_marker_framenr(act_track, act_plane_track, a); if (marker_framenr >= i) break; if (a < markersnr - 1 && generic_track_get_marker_framenr(act_track, act_plane_track, a + 1) > i) break; a++; } a = min_ii(a, markersnr - 1); if (generic_track_is_marker_enabled(act_track, act_plane_track, a)) { framenr = generic_track_get_marker_framenr(act_track, act_plane_track, a); if (framenr != i) glColor4ub(128, 128, 0, 96); else if (generic_track_is_marker_keyframed(act_track, act_plane_track, a)) glColor4ub(255, 255, 0, 196); else glColor4ub(255, 255, 0, 96); glRecti((i - sfra + clip->start_frame - 1) * framelen, 0, (i - sfra + clip->start_frame) * framelen, 4 * UI_DPI_FAC); } } } /* failed frames */ if (reconstruction->flag & TRACKING_RECONSTRUCTED) { int n = reconstruction->camnr; MovieReconstructedCamera *cameras = reconstruction->cameras; glColor4ub(255, 0, 0, 96); for (i = sfra, a = 0; i <= efra; i++) { bool ok = false; while (a < n) { if (cameras[a].framenr == i) { ok = true; break; } else if (cameras[a].framenr > i) { break; } a++; } if (!ok) glRecti((i - sfra + clip->start_frame - 1) * framelen, 0, (i - sfra + clip->start_frame) * framelen, 8 * UI_DPI_FAC); } } glDisable(GL_BLEND); /* current frame */ x = (sc->user.framenr - sfra) / (efra - sfra + 1) * ar->winx; UI_ThemeColor(TH_CFRAME); glRecti(x, 0, x + ceilf(framelen), 8 * UI_DPI_FAC); ED_region_cache_draw_curfra_label(sc->user.framenr, x, 8.0f * UI_DPI_FAC); /* solver keyframes */ glColor4ub(175, 255, 0, 255); draw_keyframe(act_object->keyframe1 + clip->start_frame - 1, CFRA, sfra, framelen, 2); draw_keyframe(act_object->keyframe2 + clip->start_frame - 1, CFRA, sfra, framelen, 2); /* movie clip animation */ if ((sc->mode == SC_MODE_MASKEDIT) && sc->mask_info.mask) { ED_mask_draw_frames(sc->mask_info.mask, ar, CFRA, sfra, efra); } }
static void draw_distortion(SpaceClip *sc, ARegion *ar, MovieClip *clip, int width, int height, float zoomx, float zoomy) { float x, y; const int n = 10; int i, j, a; float pos[2], tpos[2], grid[11][11][2]; MovieTracking *tracking = &clip->tracking; bGPdata *gpd = NULL; float aspy = 1.0f / tracking->camera.pixel_aspect; float dx = (float)width / n, dy = (float)height / n * aspy; float offsx = 0.0f, offsy = 0.0f; if (!tracking->camera.focal) return; if ((sc->flag & SC_SHOW_GRID) == 0 && (sc->flag & SC_MANUAL_CALIBRATION) == 0) return; UI_view2d_view_to_region_fl(&ar->v2d, 0.0f, 0.0f, &x, &y); glPushMatrix(); glTranslatef(x, y, 0); glScalef(zoomx, zoomy, 0); glMultMatrixf(sc->stabmat); glScalef(width, height, 0); /* grid */ if (sc->flag & SC_SHOW_GRID) { float val[4][2], idx[4][2]; float min[2], max[2]; for (a = 0; a < 4; a++) { if (a < 2) val[a][a % 2] = FLT_MAX; else val[a][a % 2] = -FLT_MAX; } zero_v2(pos); for (i = 0; i <= n; i++) { for (j = 0; j <= n; j++) { if (i == 0 || j == 0 || i == n || j == n) { BKE_tracking_distort_v2(tracking, pos, tpos); for (a = 0; a < 4; a++) { int ok; if (a < 2) ok = tpos[a % 2] < val[a][a % 2]; else ok = tpos[a % 2] > val[a][a % 2]; if (ok) { copy_v2_v2(val[a], tpos); idx[a][0] = j; idx[a][1] = i; } } } pos[0] += dx; } pos[0] = 0.0f; pos[1] += dy; } INIT_MINMAX2(min, max); for (a = 0; a < 4; a++) { pos[0] = idx[a][0] * dx; pos[1] = idx[a][1] * dy; BKE_tracking_undistort_v2(tracking, pos, tpos); minmax_v2v2_v2(min, max, tpos); } copy_v2_v2(pos, min); dx = (max[0] - min[0]) / n; dy = (max[1] - min[1]) / n; for (i = 0; i <= n; i++) { for (j = 0; j <= n; j++) { BKE_tracking_distort_v2(tracking, pos, grid[i][j]); grid[i][j][0] /= width; grid[i][j][1] /= height * aspy; pos[0] += dx; } pos[0] = min[0]; pos[1] += dy; } glColor3f(1.0f, 0.0f, 0.0f); for (i = 0; i <= n; i++) { glBegin(GL_LINE_STRIP); for (j = 0; j <= n; j++) { glVertex2fv(grid[i][j]); } glEnd(); } for (j = 0; j <= n; j++) { glBegin(GL_LINE_STRIP); for (i = 0; i <= n; i++) { glVertex2fv(grid[i][j]); } glEnd(); } } if (sc->gpencil_src == SC_GPENCIL_SRC_TRACK) { MovieTrackingTrack *track = BKE_tracking_track_get_active(&sc->clip->tracking); if (track) { int framenr = ED_space_clip_get_clip_frame_number(sc); MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr); offsx = marker->pos[0]; offsy = marker->pos[1]; gpd = track->gpd; } } else { gpd = clip->gpd; } if (sc->flag & SC_MANUAL_CALIBRATION && gpd) { bGPDlayer *layer = gpd->layers.first; while (layer) { bGPDframe *frame = layer->frames.first; if (layer->flag & GP_LAYER_HIDE) { layer = layer->next; continue; } glColor4fv(layer->color); glLineWidth(layer->thickness); glPointSize((float)(layer->thickness + 2)); while (frame) { bGPDstroke *stroke = frame->strokes.first; while (stroke) { if (stroke->flag & GP_STROKE_2DSPACE) { if (stroke->totpoints > 1) { glBegin(GL_LINE_STRIP); for (i = 0; i < stroke->totpoints - 1; i++) { float npos[2], dpos[2], len; int steps; pos[0] = (stroke->points[i].x + offsx) * width; pos[1] = (stroke->points[i].y + offsy) * height * aspy; npos[0] = (stroke->points[i + 1].x + offsx) * width; npos[1] = (stroke->points[i + 1].y + offsy) * height * aspy; len = len_v2v2(pos, npos); steps = ceil(len / 5.0f); /* we want to distort only long straight lines */ if (stroke->totpoints == 2) { BKE_tracking_undistort_v2(tracking, pos, pos); BKE_tracking_undistort_v2(tracking, npos, npos); } sub_v2_v2v2(dpos, npos, pos); mul_v2_fl(dpos, 1.0f / steps); for (j = 0; j <= steps; j++) { BKE_tracking_distort_v2(tracking, pos, tpos); glVertex2f(tpos[0] / width, tpos[1] / (height * aspy)); add_v2_v2(pos, dpos); } } glEnd(); } else if (stroke->totpoints == 1) { glBegin(GL_POINTS); glVertex2f(stroke->points[0].x + offsx, stroke->points[0].y + offsy); glEnd(); } } stroke = stroke->next; } frame = frame->next; } layer = layer->next; } glLineWidth(1.0f); glPointSize(1.0f); } glPopMatrix(); }
/* Draw all kind of tracks. */ static void draw_tracking_tracks(SpaceClip *sc, Scene *scene, ARegion *ar, MovieClip *clip, int width, int height, float zoomx, float zoomy) { float x, y; MovieTracking *tracking = &clip->tracking; ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking); ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking); MovieTrackingTrack *track, *act_track; MovieTrackingPlaneTrack *plane_track, *active_plane_track; MovieTrackingMarker *marker; int framenr = ED_space_clip_get_clip_frame_number(sc); int undistort = sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT; float *marker_pos = NULL, *fp, *active_pos = NULL, cur_pos[2]; /* ** find window pixel coordinates of origin ** */ /* UI_view2d_view_to_region_no_clip return integer values, this could * lead to 1px flickering when view is locked to selection during playbeck. * to avoid this flickering, calculate base point in the same way as it happens * in UI_view2d_view_to_region_no_clip, but do it in floats here */ UI_view2d_view_to_region_fl(&ar->v2d, 0.0f, 0.0f, &x, &y); glPushMatrix(); glTranslatef(x, y, 0); glPushMatrix(); glScalef(zoomx, zoomy, 0); glMultMatrixf(sc->stabmat); glScalef(width, height, 0); act_track = BKE_tracking_track_get_active(tracking); /* Draw plane tracks */ active_plane_track = BKE_tracking_plane_track_get_active(tracking); for (plane_track = plane_tracks_base->first; plane_track; plane_track = plane_track->next) { if ((plane_track->flag & PLANE_TRACK_HIDDEN) == 0) { draw_plane_track(sc, scene, plane_track, framenr, plane_track == active_plane_track, width, height); } } if (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT) { int count = 0; /* count */ track = tracksbase->first; while (track) { if ((track->flag & TRACK_HIDDEN) == 0) { marker = BKE_tracking_marker_get(track, framenr); if (MARKER_VISIBLE(sc, track, marker)) count++; } track = track->next; } /* undistort */ if (count) { marker_pos = MEM_callocN(2 * sizeof(float) * count, "draw_tracking_tracks marker_pos"); track = tracksbase->first; fp = marker_pos; while (track) { if ((track->flag & TRACK_HIDDEN) == 0) { marker = BKE_tracking_marker_get(track, framenr); if (MARKER_VISIBLE(sc, track, marker)) { ED_clip_point_undistorted_pos(sc, marker->pos, fp); if (track == act_track) active_pos = fp; fp += 2; } } track = track->next; } } } if (sc->flag & SC_SHOW_TRACK_PATH) { track = tracksbase->first; while (track) { if ((track->flag & TRACK_HIDDEN) == 0) draw_track_path(sc, clip, track); track = track->next; } } /* markers outline and non-selected areas */ track = tracksbase->first; fp = marker_pos; while (track) { if ((track->flag & TRACK_HIDDEN) == 0) { marker = BKE_tracking_marker_get(track, framenr); if (MARKER_VISIBLE(sc, track, marker)) { copy_v2_v2(cur_pos, fp ? fp : marker->pos); draw_marker_outline(sc, track, marker, cur_pos, width, height); draw_marker_areas(sc, track, marker, cur_pos, width, height, 0, 0); draw_marker_slide_zones(sc, track, marker, cur_pos, 1, 0, 0, width, height); draw_marker_slide_zones(sc, track, marker, cur_pos, 0, 0, 0, width, height); if (fp) fp += 2; } } track = track->next; } /* selected areas only, so selection wouldn't be overlapped by * non-selected areas */ track = tracksbase->first; fp = marker_pos; while (track) { if ((track->flag & TRACK_HIDDEN) == 0) { int act = track == act_track; marker = BKE_tracking_marker_get(track, framenr); if (MARKER_VISIBLE(sc, track, marker)) { if (!act) { copy_v2_v2(cur_pos, fp ? fp : marker->pos); draw_marker_areas(sc, track, marker, cur_pos, width, height, 0, 1); draw_marker_slide_zones(sc, track, marker, cur_pos, 0, 1, 0, width, height); } if (fp) fp += 2; } } track = track->next; } /* active marker would be displayed on top of everything else */ if (act_track) { if ((act_track->flag & TRACK_HIDDEN) == 0) { marker = BKE_tracking_marker_get(act_track, framenr); if (MARKER_VISIBLE(sc, act_track, marker)) { copy_v2_v2(cur_pos, active_pos ? active_pos : marker->pos); draw_marker_areas(sc, act_track, marker, cur_pos, width, height, 1, 1); draw_marker_slide_zones(sc, act_track, marker, cur_pos, 0, 1, 1, width, height); } } } if (sc->flag & SC_SHOW_BUNDLES) { MovieTrackingObject *object = BKE_tracking_object_get_active(tracking); float pos[4], vec[4], mat[4][4], aspy; glEnable(GL_POINT_SMOOTH); glPointSize(3.0f); aspy = 1.0f / clip->tracking.camera.pixel_aspect; BKE_tracking_get_projection_matrix(tracking, object, framenr, width, height, mat); track = tracksbase->first; while (track) { if ((track->flag & TRACK_HIDDEN) == 0 && track->flag & TRACK_HAS_BUNDLE) { marker = BKE_tracking_marker_get(track, framenr); if (MARKER_VISIBLE(sc, track, marker)) { float npos[2]; copy_v3_v3(vec, track->bundle_pos); vec[3] = 1; mul_v4_m4v4(pos, mat, vec); pos[0] = (pos[0] / (pos[3] * 2.0f) + 0.5f) * width; pos[1] = (pos[1] / (pos[3] * 2.0f) + 0.5f) * height * aspy; BKE_tracking_distort_v2(tracking, pos, npos); if (npos[0] >= 0.0f && npos[1] >= 0.0f && npos[0] <= width && npos[1] <= height * aspy) { vec[0] = (marker->pos[0] + track->offset[0]) * width; vec[1] = (marker->pos[1] + track->offset[1]) * height * aspy; sub_v2_v2(vec, npos); if (len_squared_v2(vec) < (3.0f * 3.0f)) glColor3f(0.0f, 1.0f, 0.0f); else glColor3f(1.0f, 0.0f, 0.0f); glBegin(GL_POINTS); if (undistort) glVertex3f(pos[0] / width, pos[1] / (height * aspy), 0); else glVertex3f(npos[0] / width, npos[1] / (height * aspy), 0); glEnd(); } } } track = track->next; } glPointSize(1.0f); glDisable(GL_POINT_SMOOTH); } glPopMatrix(); if (sc->flag & SC_SHOW_NAMES) { /* scaling should be cleared before drawing texts, otherwise font would also be scaled */ track = tracksbase->first; fp = marker_pos; while (track) { if ((track->flag & TRACK_HIDDEN) == 0) { marker = BKE_tracking_marker_get(track, framenr); if (MARKER_VISIBLE(sc, track, marker)) { int act = track == act_track; copy_v2_v2(cur_pos, fp ? fp : marker->pos); draw_marker_texts(sc, track, marker, cur_pos, act, width, height, zoomx, zoomy); if (fp) fp += 2; } } track = track->next; } } glPopMatrix(); if (marker_pos) MEM_freeN(marker_pos); }
static int select_groped_exec(bContext *C, wmOperator *op) { SpaceClip *sc = CTX_wm_space_clip(C); MovieClip *clip = ED_space_clip_get_clip(sc); MovieTrackingTrack *track; MovieTrackingMarker *marker; MovieTracking *tracking = &clip->tracking; ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking); int group = RNA_enum_get(op->ptr, "group"); int framenr = ED_space_clip_get_clip_frame_number(sc); track = tracksbase->first; while (track) { bool ok = false; marker = BKE_tracking_marker_get(track, framenr); if (group == 0) { /* Keyframed */ ok = marker->framenr == framenr && (marker->flag & MARKER_TRACKED) == 0; } else if (group == 1) { /* Estimated */ ok = marker->framenr != framenr; } else if (group == 2) { /* tracked */ ok = marker->framenr == framenr && (marker->flag & MARKER_TRACKED); } else if (group == 3) { /* locked */ ok = track->flag & TRACK_LOCKED; } else if (group == 4) { /* disabled */ ok = marker->flag & MARKER_DISABLED; } else if (group == 5) { /* color */ MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking); if (act_track) { ok = (track->flag & TRACK_CUSTOMCOLOR) == (act_track->flag & TRACK_CUSTOMCOLOR); if (ok && track->flag & TRACK_CUSTOMCOLOR) ok = equals_v3v3(track->color, act_track->color); } } else if (group == 6) { /* failed */ ok = (track->flag & TRACK_HAS_BUNDLE) == 0; } if (ok) { track->flag |= SELECT; if (sc->flag & SC_SHOW_MARKER_PATTERN) track->pat_flag |= SELECT; if (sc->flag & SC_SHOW_MARKER_SEARCH) track->search_flag |= SELECT; } track = track->next; } BKE_tracking_dopesheet_tag_update(tracking); WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip); return OPERATOR_FINISHED; }
void clip_delete_track(bContext *C, MovieClip *clip, MovieTrackingTrack *track) { MovieTracking *tracking = &clip->tracking; MovieTrackingStabilization *stab = &tracking->stabilization; MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking); MovieTrackingPlaneTrack *plane_track, *next_plane_track; ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking); ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking); bool has_bundle = false, update_stab = false; char track_name_escaped[MAX_NAME], prefix[MAX_NAME * 2]; if (track == act_track) tracking->act_track = NULL; if (track == stab->rot_track) { stab->rot_track = NULL; update_stab = true; } /* handle reconstruction display in 3d viewport */ if (track->flag & TRACK_HAS_BUNDLE) has_bundle = true; /* Make sure no plane will use freed track */ for (plane_track = plane_tracks_base->first; plane_track; plane_track = next_plane_track) { bool found = false; int i; next_plane_track = plane_track->next; for (i = 0; i < plane_track->point_tracksnr; i++) { if (plane_track->point_tracks[i] == track) { found = true; break; } } if (!found) { continue; } if (plane_track->point_tracksnr > 4) { int track_index; MovieTrackingTrack **new_point_tracks; new_point_tracks = MEM_mallocN(sizeof(*new_point_tracks) * (plane_track->point_tracksnr - 1), "new point tracks array"); for (i = 0, track_index = 0; i < plane_track->point_tracksnr; i++) { if (plane_track->point_tracks[i] != track) { new_point_tracks[track_index++] = plane_track->point_tracks[i]; } } MEM_freeN(plane_track->point_tracks); plane_track->point_tracks = new_point_tracks; plane_track->point_tracksnr--; } else { /* Delete planes with less than 3 point tracks in it. */ BKE_tracking_plane_track_free(plane_track); BLI_freelinkN(plane_tracks_base, plane_track); } } /* Delete f-curves associated with the track (such as weight, i.e.) */ BLI_strescape(track_name_escaped, track->name, sizeof(track_name_escaped)); BLI_snprintf(prefix, sizeof(prefix), "tracks[\"%s\"]", track_name_escaped); BKE_animdata_fix_paths_remove(&clip->id, prefix); BKE_tracking_track_free(track); BLI_freelinkN(tracksbase, track); WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip); if (update_stab) { tracking->stabilization.ok = false; WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip); } DAG_id_tag_update(&clip->id, 0); if (has_bundle) WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL); }
static void draw_movieclip_cache(SpaceClip *sc, ARegion *ar, MovieClip *clip, Scene *scene) { float x; int *points, totseg, i, a; float sfra = SFRA, efra = EFRA, framelen = ar->winx / (efra - sfra + 1); MovieTrackingTrack *act_track = BKE_tracking_track_get_active(&clip->tracking); MovieTrackingReconstruction *reconstruction = BKE_tracking_get_active_reconstruction(&clip->tracking); glEnable(GL_BLEND); /* cache background */ glColor4ub(128, 128, 255, 64); glRecti(0, 0, ar->winx, 8); /* cached segments -- could be usefu lto debug caching strategies */ BKE_movieclip_get_cache_segments(clip, &sc->user, &totseg, &points); if (totseg) { glColor4ub(128, 128, 255, 128); for (a = 0; a < totseg; a++) { float x1, x2; x1 = (points[a * 2] - sfra) / (efra - sfra + 1) * ar->winx; x2 = (points[a * 2 + 1] - sfra + 1) / (efra - sfra + 1) * ar->winx; glRecti(x1, 0, x2, 8); } } /* track */ if (act_track) { MovieTrackingTrack *track = act_track; for (i = sfra - clip->start_frame + 1, a = 0; i <= efra - clip->start_frame + 1; i++) { int framenr; MovieTrackingMarker *marker; while (a < track->markersnr) { if (track->markers[a].framenr >= i) break; if (a < track->markersnr - 1 && track->markers[a + 1].framenr > i) break; a++; } if (a < track->markersnr) marker = &track->markers[a]; else marker = &track->markers[track->markersnr - 1]; if ((marker->flag & MARKER_DISABLED) == 0) { framenr = marker->framenr; if (framenr != i) glColor4ub(128, 128, 0, 96); else if ((marker->flag & MARKER_TRACKED) == 0) glColor4ub(255, 255, 0, 196); else glColor4ub(255, 255, 0, 96); glRecti((i - sfra + clip->start_frame - 1) * framelen, 0, (i - sfra + clip->start_frame) * framelen, 4); } } } /* failed frames */ if (reconstruction->flag & TRACKING_RECONSTRUCTED) { int n = reconstruction->camnr; MovieReconstructedCamera *cameras = reconstruction->cameras; glColor4ub(255, 0, 0, 96); for (i = sfra, a = 0; i <= efra; i++) { int ok = FALSE; while (a < n) { if (cameras[a].framenr == i) { ok = TRUE; break; } else if (cameras[a].framenr > i) { break; } a++; } if (!ok) glRecti((i - sfra + clip->start_frame - 1) * framelen, 0, (i - sfra + clip->start_frame) * framelen, 8); } } glDisable(GL_BLEND); /* current frame */ x = (sc->user.framenr - sfra) / (efra - sfra + 1) * ar->winx; UI_ThemeColor(TH_CFRAME); glRecti(x, 0, x + framelen, 8); clip_draw_curfra_label(sc, x, 8.0f); /* movie clip animation */ if ((sc->mode == SC_MODE_MASKEDIT) && sc->mask_info.mask) { MaskLayer *masklay = BKE_mask_layer_active(sc->mask_info.mask); if (masklay) { MaskLayerShape *masklay_shape; glColor4ub(255, 175, 0, 255); glBegin(GL_LINES); for (masklay_shape = masklay->splines_shapes.first; masklay_shape; masklay_shape = masklay_shape->next) { i = masklay_shape->frame; /* glRecti((i - sfra) * framelen, 0, (i - sfra + 1) * framelen, 4); */ /* use a line so we always see the keyframes */ glVertex2i((i - sfra) * framelen, 0); glVertex2i((i - sfra) * framelen, (i == CFRA) ? 22 : 10); } glEnd(); } } }
static int mouse_select(bContext *C, float co[2], int extend) { SpaceClip *sc = CTX_wm_space_clip(C); MovieClip *clip = ED_space_clip_get_clip(sc); MovieTracking *tracking = &clip->tracking; ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking); ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking); MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking); MovieTrackingTrack *track; MovieTrackingPlaneTrack *plane_track; float distance_to_track, distance_to_plane_track; track = find_nearest_track(sc, tracksbase, co, &distance_to_track); plane_track = find_nearest_plane_track(sc, plane_tracks_base, co, &distance_to_plane_track); /* Between track and plane we choose closest to the mouse for selection here. */ if (track && plane_track) { if (distance_to_track < distance_to_plane_track) { plane_track = NULL; } else { track = NULL; } } if (!extend) { delect_all_plane_tracks(plane_tracks_base); } if (track) { int area = track_mouse_area(C, co, track); if (!extend || !TRACK_VIEW_SELECTED(sc, track)) area = TRACK_AREA_ALL; if (extend && TRACK_AREA_SELECTED(track, area)) { if (track == act_track) { BKE_tracking_track_deselect(track, area); } else { clip->tracking.act_track = track; clip->tracking.act_plane_track = NULL; } } else { if (area == TRACK_AREA_POINT) area = TRACK_AREA_ALL; BKE_tracking_track_select(tracksbase, track, area, extend); clip->tracking.act_track = track; clip->tracking.act_plane_track = NULL; } } else if (plane_track) { if (!extend) { delect_all_tracks(tracksbase); } if (PLANE_TRACK_VIEW_SELECTED(plane_track)) { if (extend) { plane_track->flag &= ~SELECT; } } else { plane_track->flag |= SELECT; } clip->tracking.act_track = NULL; clip->tracking.act_plane_track = plane_track; } if (!extend) { sc->xlockof = 0.0f; sc->ylockof = 0.0f; } BKE_tracking_dopesheet_tag_update(tracking); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL); return OPERATOR_FINISHED; }
void BKE_movieclip_update_scopes(MovieClip *clip, MovieClipUser *user, MovieClipScopes *scopes) { if (scopes->ok) return; if (scopes->track_preview) { IMB_freeImBuf(scopes->track_preview); scopes->track_preview = NULL; } if (scopes->track_search) { IMB_freeImBuf(scopes->track_search); scopes->track_search = NULL; } scopes->marker = NULL; scopes->track = NULL; scopes->track_locked = true; if (clip) { MovieTrackingTrack *act_track = BKE_tracking_track_get_active(&clip->tracking); if (act_track) { MovieTrackingTrack *track = act_track; int framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, user->framenr); MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr); scopes->marker = marker; scopes->track = track; if (marker->flag & MARKER_DISABLED) { scopes->track_disabled = true; } else { ImBuf *ibuf = BKE_movieclip_get_ibuf(clip, user); scopes->track_disabled = false; if (ibuf && (ibuf->rect || ibuf->rect_float)) { MovieTrackingMarker undist_marker = *marker; if (user->render_flag & MCLIP_PROXY_RENDER_UNDISTORT) { int width, height; float aspy = 1.0f / clip->tracking.camera.pixel_aspect; BKE_movieclip_get_size(clip, user, &width, &height); undist_marker.pos[0] *= width; undist_marker.pos[1] *= height * aspy; BKE_tracking_undistort_v2(&clip->tracking, undist_marker.pos, undist_marker.pos); undist_marker.pos[0] /= width; undist_marker.pos[1] /= height * aspy; } scopes->track_search = BKE_tracking_get_search_imbuf(ibuf, track, &undist_marker, true, true); scopes->undist_marker = undist_marker; scopes->frame_width = ibuf->x; scopes->frame_height = ibuf->y; scopes->use_track_mask = track->flag & TRACK_PREVIEW_ALPHA; } IMB_freeImBuf(ibuf); } if ((track->flag & TRACK_LOCKED) == 0) { float pat_min[2], pat_max[2]; scopes->track_locked = false; /* XXX: would work fine with non-transformed patterns, but would likely fail * with transformed patterns, but that would be easier to debug when * we'll have real pattern sampling (at least to test) */ BKE_tracking_marker_pattern_minmax(marker, pat_min, pat_max); scopes->slide_scale[0] = pat_max[0] - pat_min[0]; scopes->slide_scale[1] = pat_max[1] - pat_min[1]; } } } scopes->framenr = user->framenr; scopes->ok = true; }
static int mask_parent_set_exec(bContext *C, wmOperator *UNUSED(op)) { Mask *mask = CTX_data_edit_mask(C); MaskLayer *masklay; /* parent info */ SpaceClip *sc = CTX_wm_space_clip(C); MovieClip *clip = ED_space_clip_get_clip(sc); MovieTracking *tracking; MovieTrackingTrack *track; MovieTrackingPlaneTrack *plane_track; MovieTrackingObject *tracking_object; /* done */ int framenr, parent_type; float parmask_pos[2], orig_corners[4][2]; char *sub_parent_name; if (ELEM(NULL, sc, clip)) { return OPERATOR_CANCELLED; } framenr = ED_space_clip_get_clip_frame_number(sc); tracking = &clip->tracking; tracking_object = BKE_tracking_object_get_active(&clip->tracking); if (tracking_object == NULL) { return OPERATOR_CANCELLED; } if ((track = BKE_tracking_track_get_active(tracking)) != NULL) { MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr); float marker_pos_ofs[2]; add_v2_v2v2(marker_pos_ofs, marker->pos, track->offset); BKE_mask_coord_from_movieclip(clip, &sc->user, parmask_pos, marker_pos_ofs); sub_parent_name = track->name; parent_type = MASK_PARENT_POINT_TRACK; memset(orig_corners, 0, sizeof(orig_corners)); } else if ((plane_track = BKE_tracking_plane_track_get_active(tracking)) != NULL) { MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track, framenr); zero_v2(parmask_pos); sub_parent_name = plane_track->name; parent_type = MASK_PARENT_PLANE_TRACK; memcpy(orig_corners, plane_marker->corners, sizeof(orig_corners)); } else { return OPERATOR_CANCELLED; } for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) { MaskSpline *spline; int i; if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) { continue; } for (spline = masklay->splines.first; spline; spline = spline->next) { for (i = 0; i < spline->tot_point; i++) { MaskSplinePoint *point = &spline->points[i]; if (MASKPOINT_ISSEL_ANY(point)) { point->parent.id_type = ID_MC; point->parent.id = &clip->id; point->parent.type = parent_type; BLI_strncpy(point->parent.parent, tracking_object->name, sizeof(point->parent.parent)); BLI_strncpy(point->parent.sub_parent, sub_parent_name, sizeof(point->parent.sub_parent)); copy_v2_v2(point->parent.parent_orig, parmask_pos); memcpy(point->parent.parent_corners_orig, orig_corners, sizeof(point->parent.parent_corners_orig)); } } } } WM_event_add_notifier(C, NC_MASK | ND_DATA, mask); DAG_id_tag_update(&mask->id, 0); return OPERATOR_FINISHED; }
static int set_plane_exec(bContext *C, wmOperator *op) { SpaceClip *sc = CTX_wm_space_clip(C); MovieClip *clip = ED_space_clip_get_clip(sc); Scene *scene = CTX_data_scene(C); MovieTracking *tracking = &clip->tracking; MovieTrackingObject *tracking_object; MovieTrackingTrack *track, *axis_track = NULL, *act_track; ListBase *tracksbase; Object *object; Object *camera = get_camera_with_movieclip(scene, clip); Depsgraph *depsgraph = CTX_data_depsgraph(C); int tot = 0; float vec[3][3], mat[4][4], obmat[4][4], newmat[4][4], orig[3] = {0.0f, 0.0f, 0.0f}; int plane = RNA_enum_get(op->ptr, "plane"); float rot[4][4] = { {0.0f, 0.0f, -1.0f, 0.0f}, {0.0f, 1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f, 1.0f}, }; /* 90 degrees Y-axis rotation matrix */ if (count_selected_bundles(C) != 3) { BKE_report(op->reports, RPT_ERROR, "Three tracks with bundles are needed to orient the floor"); return OPERATOR_CANCELLED; } tracking_object = BKE_tracking_object_get_active(tracking); tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object); act_track = BKE_tracking_track_get_active(tracking); object = get_orientation_object(C); if (object == NULL) { BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on"); return OPERATOR_CANCELLED; } BKE_tracking_get_camera_object_matrix(scene, camera, mat); /* Get 3 bundles to use as reference. */ track = tracksbase->first; while (track && tot < 3) { if (track->flag & TRACK_HAS_BUNDLE && TRACK_VIEW_SELECTED(sc, track)) { mul_v3_m4v3(vec[tot], mat, track->bundle_pos); if (tot == 0 || track == act_track) { copy_v3_v3(orig, vec[tot]); } else { axis_track = track; } tot++; } track = track->next; } sub_v3_v3(vec[1], vec[0]); sub_v3_v3(vec[2], vec[0]); /* Construct ortho-normal basis. */ unit_m4(mat); if (plane == 0) { /* floor */ cross_v3_v3v3(mat[0], vec[1], vec[2]); copy_v3_v3(mat[1], vec[1]); cross_v3_v3v3(mat[2], mat[0], mat[1]); } else if (plane == 1) { /* wall */ cross_v3_v3v3(mat[2], vec[1], vec[2]); copy_v3_v3(mat[1], vec[1]); cross_v3_v3v3(mat[0], mat[1], mat[2]); } normalize_v3(mat[0]); normalize_v3(mat[1]); normalize_v3(mat[2]); /* Move to origin point. */ mat[3][0] = orig[0]; mat[3][1] = orig[1]; mat[3][2] = orig[2]; if (tracking_object->flag & TRACKING_OBJECT_CAMERA) { invert_m4(mat); BKE_object_to_mat4(object, obmat); mul_m4_m4m4(mat, mat, obmat); mul_m4_m4m4(newmat, rot, mat); BKE_object_apply_mat4(object, newmat, 0, 0); /* Make camera have positive z-coordinate. */ if (object->loc[2] < 0) { invert_m4(rot); mul_m4_m4m4(newmat, rot, mat); BKE_object_apply_mat4(object, newmat, 0, 0); } } else { BKE_object_apply_mat4(object, mat, 0, 0); } BKE_object_where_is_calc(depsgraph, scene, object); set_axis(scene, object, clip, tracking_object, axis_track, 'X'); DEG_id_tag_update(&clip->id, 0); DEG_id_tag_update(&object->id, ID_RECALC_TRANSFORM); WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip); WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); return OPERATOR_FINISHED; }